syntastic complaining about ES6 module syntax - javascript

I love syntastic for javascript but I am using the new ES6 module tranpiler and syntastic is not happy about these type of statements:
import Typeahead from './lib/components/ember-typeahead';
Is there anyway that I can keep syntastic quiet about this type of statement?

Syntastic will use JSHint to check JavaScript syntax if it's available (which I recommend over jslint).
JSHint supports es6 syntax with the esnext flag, which includes support for the export and import module syntax.
I suggest adding a .jshintrc file to your project to control JSHint's behavior (and thus Syntastic's) for your entire project:
{
"esnext": true
}
Note: be careful, since using the esnext flag will add support for all of es6's new language sytax that JSHint currently supports, not just the module syntax.
Note: esnext has now been deprecated in favour of the esversion syntax.
{
"esversion": 6
}

To work around this, I'd suggest the following steps as recommended here: Configure Vim for React:
Install eslint and babel-eslint:
npm install -g eslint babel-eslint
Create a local .eslintrc config in your project or a global ~/.eslintrc configuration:
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true
},
"settings": {
"ecmascript": 6
},
"rules": {
"strict": 0 // you can add more rules if you want
}
}
Finally, configure syntastic to use eslint:
let g:syntastic_javascript_checkers = ['eslint']

Related

"Parsing error: Unexpected token import" when accessing import.meta.url (Cloud9 IDE)

With the following node.js code:
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
I am seeing the following lint error relating to the import.meta.url reference:
This snippet is to replicate __filename and __dirname in ESM as per node.js guidance. The same error is given when using import.meta.url as follows... which is also in the official guidance:
import { readFileSync } from 'fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
I have looked at this but it doesn't solve my problem. This is specifically within the Cloud9 IDE... not the current AWS Cloud9 but a self-hosted Cloud9 based on this repo (last updated 4 years ago). The only guidance from (AWS) Cloud9 is on this page:
I can get certain basic rules to work using this .eslintrc file, e.g.
{
rules: {
semi: ["error", "never"]
}
}
So I know that the config file is taking effect in the IDE. But can't see the appropriate rule to disable the "unexpected token import" error.
EDIT: the following seem relevant but I cannot determine if it has ever really reached a conclusion:
https://github.com/eslint/eslint/issues/12518
https://github.com/eslint/eslint/pull/13196
https://github.com/eslint/eslint/issues/13133
This is actually an educated guess, since I'm not using the Cloud9 IDE. If your .eslintrc file is being recognized, what you need to add there are the proper parser options, e.g.:
{
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"rules": {
"semi": ["error", "never"]
}
}
The reason is that the ESLint parser treats by default all JavaScript sources as ES5 scripts, while the import.meta syntax is only allowed in modules since ECMAScript 2020.
Update
The setting "ecmaVersion": 2020 is supported in ESLint 6 onwards. Another option to have import.meta recognized is using a custom parser like Babel.
The packages to install for the Babel parser are #babel/core and #babel/eslint-parser.
And the relevant settings in .eslintrc are here:
{
"parser": "#babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2020,
"requireConfigFile": false
},
Note: I couldn't find out which versions of ESLint are supported by the Babel parser in the documentation in their repo (link above). I can only see in the code that ESLint 7 and 8 are supported. If the current version of Babel does not work with your version of ESLint, you may have to try installing older releases and see if they work. And in that case, an additional plugin like syntax-import-meta may be required.

Why is ESLint complaining about a syntax error when I can run my code fine in Node? "Parsing error: Unexpected token =" [duplicate]

ESLint is throwing a Parsing error: Unexpected token = error when I try to lint my Es6 classes. What configuration parameter am I missing to enable fat arrow class methods in eslint?
Sample class:
class App extends React.Component{
...
handleClick = (evt) => {
...
}
}
.eslint
{
"ecmaFeatures": {
"jsx": true,
"modules":true,
"arrowFunctions":true,
"classes":true,
"spread":true,
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"rules": {
"strict": 0,
"no-underscore-dangle": 0,
"quotes": [
2,
"single"
],
}
}
If you want to use experimental features (such as arrows as class methods) you need to use babel-eslint as a parser. Default parser (Espree) doesn't support experimental features.
First install babel-eslint:
npm i -D babel-eslint
Then add the following to your .eslintrc.json file:
"parser": "babel-eslint"
First install these plugins:
npm i -D babel-eslint eslint-plugin-babel
Then add these settings to your ESLint config file:
{
"plugins": [ "babel" ],
"parser": "babel-eslint",
"rules": {
"no-invalid-this": 0,
"babel/no-invalid-this": 1,
}
}
This way you can use fat arrow class methods plus you will not get any no-invalid-this errors from ESLint.
From what I read in the error message Parsing error: Unexpected token = it looks like more a parser error than linter one.
Assuming you are using Babel as your JavaScript compiler/transpiler and babel-eslint as your ESLint parser, chances are that it is Babel complaining about the syntax, not ESLint.
The issue is not about the arrow functions but something more experimental (ES7??) that I think it is called property initializer or class instance field (or both :) ).
If you want to use this new syntax/feature you need to enable preset-stage-1 in Babel. This preset includes the syntax-class-properties plugin that allows that syntax.
Summing up:
Install babel preset:
npm install babel-preset-stage-1
Add this preset to the list of your presets (I suppose you are already using es2015 and react presets), either in your .babelrc or in your babel-loader query field if you are using webpack.
"presets": ["es2015", "stage-1", "react"]
I came across the same problem today
and #dreyescat 's answer works for me.
By default, babel uses 3 presets: es2015, react, stage-2
Screenshot with "Parsing error: Unexpected token ="
Then if you also select the stage-1preset, the error is gone
Screenshot with no error
You can test it on the bebeljs.io site yourself
2021 Update: Be sure you're using #babel/eslint-parser and not the deprecated babel-eslint
Remove the old package if necessary: yarn remove babel-eslint or npm uninstall babel-eslint
yarn add --dev #babel/eslint-parser or npm install --save-dev #babel/eslint-parser
In .eslintrc add "parser": "#babel/eslint-parser"
Optionally, this answer suggests including "requireConfigFile": false in .eslintrc to prevent eslint from searching for unnecessary config files:
{
...
"parserOptions": {
...
"requireConfigFile": false,
}
}
If this still doesn't work, try checking whether your system is using a globally installed eslint (and removing it).
My other problem was eslint was using a globally installed version instead of my local version, and the global eslint can't access my locally installed babel-eslint parser. Further, since my globally installed eslint was installed on a different version of node, removing it was non-trivial.
Checking if your system is using global versus local eslint.
Install babel-eslint following #spencer.sm's answer for your local eslint.
From the terminal, check if you get different output from running eslint . and npx eslint .. If you get different output it's likely that it's your global eslint running that can't access babel-eslint.
Uninstalling the global eslint
For most people, the following commands should uninstall eslint with npm (uninstall global package with npm) and yarn (uninstall global package with yarn):
# npm
npm uninstall -g eslint
npm uninstall eslint
# yarn
yarn global remove eslint
Next, run npx eslint . to see if things work. If it doesn't, which it didn't for me, you need to take an extra step to remove the globally installed eslint.
From this answer, I learned that I had installed eslint on a system version of Node instead of my current version of Node (I use nvm). Follow these simple steps to remove the global eslint and you should be good to go!
Your sample isn't valid ES6, so there's no way to configure eslint to allow it

Do Any JavaScript Test Frameworks Support ES Modules

Do any test frameworks support tests that use the new ES Modules syntax? I have a JS application which heavily uses .mjs files with ES Modules. I tried Jest and Jasmine, both of which throw errors when I try to write run tests for my app. I need to test this file:
math.mjs
export function add(a, b) {
return a + b;
}
As of February 2022, this is what I saw:
Jasmine: built-in support.
Jest: built-in experimental support, requires configuration to code transformations and a node flag.
Mocha: built-in experimental support lacks some features such as watch mode.
Tape: built-in support (not mentioned in docs).
AVA: built-in support (not mentioned in released docs, but there's a recent commit to the docs switching all examples to esm)
UVU: built-in support explicitly mentioned in the docs
Other test runners with support for ES Modules are:
AVA: AVA 4 explicitly mentions ESM, but I've also used AVA 3 with ES modules without problems
UVU: A lightweight test runner that supports ES Modules and does not pull tons of dependencies into the project
You can use the esm package with Jasmine. Not sure about Jest though 🤔
math.spec.js
import { add } from './math.mjs';
describe('Add', () => {
it('should add 3 and 2', () => {
expect(add(3,2)).toBe(5);
});
});
Install and run
$ yarn global add jasmine esm
$ jasmine --require=esm
Randomized with seed 44366
Started
.
1 spec, 0 failures
Finished in 0.004 seconds
I tried Vitest and it worked like a charm. My goal was to build a publishable library with typescript. The library was part of a monorepo built with Nxw with "type": "module" in package.json and the following in my tsconfig.json:
"compilerOptions": {
"module": "ESNext",
"target": "ES6",
"moduleResolution": "node"
}
It worked with 0 configuration, and I tried testing functions that used both CJS and ESM type imports from 3rd party packages.
On a side note, I really like the clean syntax. Plus, vitest also supports testing components built with React/Vue.
The project Japa works with ESM and Typescript, and works perfectly in my set-up (Node.js 16.x with "type": "module" and .js files). The only issue I got was easy to solve, so you should give it a try

Where should I insert '#babel/polyfill' into?: main.js or each modules [duplicate]

I just started to use Babel to compile my ES6 javascript code into ES5. When I start to use Promises it looks like it's not working. The Babel website states support for promises via polyfills.
Without any luck, I tried to add:
require("babel/polyfill");
or
import * as p from "babel/polyfill";
With that I'll get the following error on my app bootstrapping:
Cannot find module 'babel/polyfill'
I searched for the module but it seems I'm missing some fundamental thing here. I also tried to add the old and good bluebird NPM but it looks like it's not working.
How to use the polyfills from Babel?
This changed a bit in babel v6.
From the docs:
The polyfill will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node.
Installation:
$ npm install babel-polyfill
Usage in Node / Browserify / Webpack:
To include the polyfill you need to require it at the top of the entry point to your application.
require("babel-polyfill");
Usage in Browser:
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
The Babel docs describe this pretty concisely:
Babel includes a polyfill that includes a custom regenerator runtime
and core.js.
This will emulate a full ES6 environment. This polyfill is
automatically loaded when using babel-node and babel/register.
Make sure you require it at the entry-point to your application, before anything else is called. If you're using a tool like webpack, that becomes pretty simple (you can tell webpack to include it in the bundle).
If you're using a tool like gulp-babel or babel-loader, you need to also install the babel package itself to use the polyfill.
Also note that for modules that affect the global scope (polyfills and the like), you can use a terse import to avoid having unused variables in your module:
import 'babel/polyfill';
For Babel version 7, if your are using #babel/preset-env, to include polyfill all you have to do is add a flag 'useBuiltIns' with the value of 'usage' in your babel configuration. There is no need to require or import polyfill at the entry point of your App.
With this flag specified, babel#7 will optimize and only include the polyfills you needs.
To use this flag, after installation:
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install --save #babel/polyfill
Simply add the flag:
useBuiltIns: "usage"
to your babel configuration file called "babel.config.js" (also new to Babel#7), under the "#babel/env" section:
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage" // <-----------------*** add this
}
]
];
return { presets };
};
Reference:
usage#polyfill
babel-polyfill#usage-in-node-browserify-webpack
babel-preset-env#usebuiltins
Update Aug 2019:
With the release of Babel 7.4.0 (March 19, 2019) #babel/polyfill is deprecated. Instead of installing #babe/polyfill, you will install core-js:
npm install --save core-js#3
A new entry corejs is added to your babel.config.js
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage",
corejs: 3 // <----- specify version of corejs used
}
]
];
return { presets };
};
see example: https://github.com/ApolloTang/stackoverflow-eg--babel-v7.4.0-polyfill-w-core-v3
Reference:
7.4.0 Released: core-js 3, static private methods and partial
application
core-js#3, babel and a look into the future
If your package.json looks something like the following:
...
"devDependencies": {
"babel": "^6.5.2",
"babel-eslint": "^6.0.4",
"babel-polyfill": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.3.0",
...
And you get the Cannot find module 'babel/polyfill' error message, then you probably just need to change your import statement FROM:
import "babel/polyfill";
TO:
import "babel-polyfill";
And make sure it comes before any other import statement (not necessarily at the entry point of your application).
Reference: https://babeljs.io/docs/usage/polyfill/
First off, the obvious answer that no one has provided, you need to install Babel into your application:
npm install babel --save
(or babel-core if you instead want to require('babel-core/polyfill')).
Aside from that, I have a grunt task to transpile my es6 and jsx as a build step (i.e. I don't want to use babel/register, which is why I am trying to use babel/polyfill directly in the first place), so I'd like to put more emphasis on this part of #ssube's answer:
Make sure you require it at the entry-point to your application,
before anything else is called
I ran into some weird issue where I was trying to require babel/polyfill from some shared environment startup file and I got the error the user referenced - I think it might have had something to do with how babel orders imports versus requires but I'm unable to reproduce now. Anyway, moving import 'babel/polyfill' as the first line in both my client and server startup scripts fixed the problem.
Note that if you instead want to use require('babel/polyfill') I would make sure all your other module loader statements are also requires and not use imports - avoid mixing the two. In other words, if you have any import statements in your startup script, make import babel/polyfill the first line in your script rather than require('babel/polyfill').
babel-polyfill allows you to use the full set of ES6 features beyond
syntax changes. This includes features such as new built-in objects
like Promises and WeakMap, as well as new static methods like
Array.from or Object.assign.
Without babel-polyfill, babel only allows you to use features like
arrow functions, destructuring, default arguments, and other
syntax-specific features introduced in ES6.
https://www.quora.com/What-does-babel-polyfill-do
https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423
Like Babel says in the docs, for Babel > 7.4.0 the module #babel/polyfill is deprecated, so it's recommended to use directly core-js and regenerator-runtime libraries that before were included in #babel/polyfill.
So this worked for me:
npm install --save core-js#3.6.5
npm install regenerator-runtime
then add to the very top of your initial js file:
import 'core-js/stable';
import 'regenerator-runtime/runtime';

Private/public modifiers with Typescript and eslint

How to configure eslint to allow Typescript class member modifiers (private, public)?
Currently if I write:
class Foo {
constructor(private bar) {
}
}
eslint tells me: error Parsing error: Unexpected token
I'm using "parser": "babel-eslint" in my .eslintrc
TSLint is deprecated
Try #typescript-eslint/eslint-plugin package instead.
Check this for more information about typescript eslint plugin.
babel-eslint doesn't support TypeScript. You might be better off using TSLint instead.

Categories