Declaring babel plugins for #babel/eslint-parser in .eslintrc - javascript

I've been trying for a while now to get #babel/plugin-proposal-class-properties plugin to work nicely with #babel/eslint-parser and eslint without success.
This is my .eslintrc.js:
...
"parser": "#babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 11,
"requireConfigFile": false,
},
"plugins": [
"#babel",
],
...
And these are the related installed packages:
+-- #babel/core#7.11.1
+-- #babel/eslint-parser#7.11.3
+-- #babel/eslint-plugin#7.11.3
+-- #babel/plugin-proposal-class-properties#7.10.4
+-- eslint#7.7.0
Under this configuration, ESLint errors with this message:
Parsing error: \eg\example.js: Support for the experimental syntax 'classPrivateProperties' isn't currently enabled (xx:yy): (Fatal)
But if I add #babel/plugin-proposal-class-properties to plugins in .eslintrc.js like this:
"plugins": [
"#babel",
"#babel/plugin-proposal-class-properties",
],
I get this error:
Error while running ESLint: Failed to load plugin '#babel/plugin-proposal-class-properties' declared in '.eslintrc.js': Cannot find module '#babel/eslint-plugin-plugin-proposal-class-properties'.
It seems like this isn't the correct way to declare plugins for #babel/eslint-parser in .eslintrc.js. Still, I suspect it is possible due to this quote here:
#babel/eslint-parser also supports applying Babel configuration through your ESLint configuration.
So my question is:
Is it actually possible to declare babel plugins in .eslintrc? If so how exactly?

It's actually simpler than I thought...
So it turns out that since #babel/plugin-proposal-class-properties is a babel plugin, it needs to be declared in the plugins property of babel's configuration. According to the documentation of #babel/eslint-parser, those can be passed in with babelOptions property.
Therefore it's really as simple as this:
...
"parserOptions": {
...
"babelOptions": {
"plugins": [
"#babel/plugin-proposal-class-properties",
...
],
},
},
"plugins": [
"#babel",
],
...

When using #babel/eslint-parser as eslintrc parser, I met this question too.
Just like this question.
For example, the eslintrc used by eslint node api in a global cli , and the cli provide a command A.
After go to the directory B, executing command A.The process.cwd() is B directory, but the #babel/xxx deps is in cli node_modules.The babel/core can not find plugins in B.
Parsing error: Cannot find module '#babel/plugin-proposal-decorators'\nRequire stack:
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/core/lib/config/files/plugins.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/core/lib/config/files/index.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/core/lib/index.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/eslint-parser/lib/worker/babel-core.cjs
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/eslint-parser/lib/worker/handle-message.cjs
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/eslint-parser/lib/client.cjs
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#babel/eslint-parser/lib/index.cjs
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#eslint/eslintrc/lib/config-array-factory.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/#eslint/eslintrc/lib/index.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/eslint/lib/cli-engine/cli-engine.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/eslint/lib/cli-engine/index.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/eslint/lib/api.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/node_modules/test-a-es-checker/dist/index.js
- /Users/a1/.nvm/versions/node/v14.16.1/lib/node_modules/test-a-cli/dist/index.js
I resolved it by provide cwd for babelOption in eslintrc.
module.exports = {
...
parser: '#babel/eslint-parser',
babelOptions: {
cwd: __dirname, // The working directory that all paths in the programmatic options will be resolved relative to.
presets: ['#babel/preset-env', '#babel/preset-react', '#babel/preset-typescript'],
plugins: [
['#babel/plugin-proposal-decorators', { legacy: true }],
['#babel/plugin-proposal-class-properties', { loose: true }],
],
},
...
};

Related

Module parse failed: Unexpected token ? Optional chaining not recognised in threejs svgloader.js [duplicate]

Project setup:
Vuejs 3
Webpack 4
Babel
TS
We created the project using vue-cli and add the dependency to the library.
We then imported a project (Vue Currency Input v2.0.0) that uses optional chaining. But we get the following error while executing the serve script:
error in ./node_modules/vue-currency-input/dist/index.esm.js
Module parse failed: Unexpected token (265:36)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| getMinValue() {
| let min = this.toFloat(-Number.MAX_SAFE_INTEGER);
> if (this.options.valueRange?.min !== undefined) {
| min = Math.max(this.options.valueRange?.min, this.toFloat(-Number.MAX_SAFE_INTEGER));
| }
I read that Webpack 4 doesn't support optional chaining by default. So, we added the Babel plugin for optional chaining. This is our babel.config.js file:
module.exports = {
presets: ["#vue/cli-plugin-babel/preset"],
plugins: ["#babel/plugin-proposal-optional-chaining"],
};
(But, if I am correct, this plugin is now enable by default in the babel-preset. So this modification might be useless ^^)
One thing that I don't understand is that we can use optional chaining in the .vue files.
I created a SandBox with all the files: SandBox
How could I solve this error?
I was able to overcome this issue using #babel/plugin-proposal-optional-chaining, but for me the only way I could get Webpack to use the Babel plugin was to shove the babel-loader configuration through the Webpack options in vue.config.js. Here is a minimal vue.config.js:
const path = require('path');
module.exports = {
chainWebpack: config => {
config.module
.rule('supportChaining')
.test(/\.js$/)
.include
.add(path.resolve('node_modules/PROBLEM_MODULE'))
.end()
.use('babel-loader')
.loader('babel-loader')
.tap(options => ({ ...options,
plugins : ['#babel/plugin-proposal-optional-chaining']
}))
.end()
}
};
NB replace "PROBLEM_MODULE" in the above with the module where you have the problem.
Surprisingly I did not need to install #babel/plugin-proposal-optional-chaining with NPM. I did a go/no-go test with an app scaffolded with #vue/cli 4.5.13, in my case without typescript. I imported the NPM module that has been causing my grief (#vime/vue-next 5.0.31 BTW), ran the serve script and got the Unexpected token error on a line containing optional chaining. I then plunked the above vue.config.js into the project root and ran the serve script again, this time with no errors.
My point is it appears this problem can be addressed without polluting one's development environment very much.
The Vue forums are in denial about this problem, claiming Vue 3 supports optional chaining. Apparently not, however, in node modules. A post in this thread by atflick on 2/26/2021 was a big help.
Had same issue with Vue 2 without typescript.
To fix this you need to force babel preset to include optional chaining rule:
presets: [
[
'#vue/cli-plugin-babel/preset',
{
include: ['#babel/plugin-proposal-optional-chaining'],
},
],
],
Can also be achieved by setting old browser target in browserslist config.
Most importantly, you need to add your failing module to transpileDependencies in vue.config.js:
module.exports = {
...
transpileDependencies: ['vue-currency-input],
}
This is required, because babel by default will exclude all node_modules from transpilation (mentioned in vue cli docs), thus no configured plugins will be applied.
I had a similar problem. I'm using nuxt but my .babelrc file looks like the below, and got it working for me.
{
"presets": [
["#babel/preset-env"]
],
"plugins":[
["#babel/plugin-transform-runtime",
{
"regenerator": true
}
]
],
"env": {
"test": {
"plugins": [
["transform-regenerator", {
"regenerator": true
}],
"#babel/plugin-transform-runtime"
],
"presets": [
["#babel/preset-env", {
"useBuiltIns": false
}]
]
}
}
}
I managed to fix the solution by adding these lines to package.json:
...
"scripts": {
"preinstall": "npx npm-force-resolutions",
...
},
"resolutions": {
"acorn": "8.0.1"
},
...

Why Jest failing on node-fetch giving syntax error on import

I'm trying to understand how to fix the following error using Jest in my unit tests in NodeJS.
The test run with this command "test": "NODE_ENV=test jest spec/* -i --coverage --passWithNoTests",
I'm also using babel and this is my config
{
"presets": [["#babel/env", { "targets": { "node": "current" } }]],
"plugins": [
"#babel/plugin-syntax-dynamic-import",
["babel-plugin-inline-import", { "extensions": [".gql"] }],
["#babel/plugin-proposal-decorators", { "legacy": true }]
]
}
In package.json I have this
"jest": {
"verbose": true,
"collectCoverageFrom": [
"spec/**/*.js"
]
},
I tried several guides online but cannot find a solution to this
You've got Jest successfully configured to transform your code, but it is not transforming modules that you're importing—in this case node-fetch, which has the import keyword in its source code (as seen in your error). This is because, by default, Jest is configured not to transform files in node_modules:
transformIgnorePatterns [array]
Default: ["/node_modules/", "\.pnp\.[^\/]+$"]
An array of regexp pattern strings that are matched against all source file paths before transformation. If the file path matches any of the patterns, it will not be transformed.
You can set transformIgnorePatterns to exclude certain packages in node_modules with a jest.config.js like this:
const esModules = [
'node-fetch',
'data-uri-to-buffer',
'fetch-blob',
'formdata-polyfill',
].join('|');
module.exports = {
transformIgnorePatterns: [
`/node_modules/(?!${esModules})`,
'\\.pnp\\.[^\\/]+$',
],
};
(see https://github.com/nrwl/nx/issues/812#issuecomment-429420861)
If you have .babelrc try to rename it to babel.config.js
Source:
https://babeljs.io/docs/en/configuration#whats-your-use-case
but also this (there's more in the discussion)
Jest won't transform the module - SyntaxError: Cannot use import statement outside a module

Jest cannot locate #babel/code-frame when trying to use # alias

Our app imports files using import ES2015 style syntax, utilizing Webpack 4.6.0 native support for ES2015 modules. We also use an alias to shorten our relative file paths.
Webpack.conf.js
resolve: {
extensions: ['.js', '.json', '.less'],
alias: {
'#': resolve('public/js'),
'handlebars': 'handlebars/dist/handlebars.js',
},
modules: ['less', 'node_modules']
},
example.js
import widget from '#/widgets/widget';
file structure
- webpack.conf.js
- .babelrc
- test/
- public/
- - js/
- - - widgets/
- - - - widget.js
When I imported for example example.js, which has an alias'd import, Jest would throw an error, "cannot resolve module '#/widgets/widget'.
According to a remarkably specific article as well as the Jest documentation, the solution is to use Jest's ModuleNameMapper config property to set up matching alias'. I have attempted to do so:
package.json
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
"#(.*)$": "<rootDir>/public/js/$1"
},
"verbose": true,
"transform": {
"^.+\\.js$": "babel-jest"
},
"globals": {
"NODE_ENV": "test"
},
"moduleFileExtensions": [
"js"
],
"moduleDirectories": [
"node_modules"
]
},
As well as properly configure babel:
.babelrc
{
"presets": [
[
"env",
{
"modules": false,
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
],
"es2015",
"stage-2"
],
"plugins": [
"syntax-dynamic-import"
]
}
Now, when I run Jest (with the --no-cache flag just in case), I get this error:
test/test.test.js
● Test suite failed to run
Configuration error:
Could not locate module #babel/code-frame (mapped as /home/calebjay/Documents/ide/public/js/babel/code-frame)
Please check:
"moduleNameMapper": {
"/#(.*)$/": "/home/calebjay/Documents/ide/public/js/$1"
},
"resolver": undefined
I can't find #babel/code-frame anywhere outside of package-lock.json, and just for giggles I stripped all mentions of #{{anything}} from there and ran tests again, same result.
Is jest stepping over babel somehow? How can I get my tests to run with Jest using aliases?
EDIT: To try to narrow down what is calling #babel/code-frame, I tried deleting es2015 and stage-2 from .babelrc, to no effect. I tried deleting the transform property of the Jest config in package.json, to no effect. I tried deleting the env.test.plugins property from .babelrc, to no effect. Same error.
EDIT2: Thinking maybe some other package is requiring it, I checked package.json. It seems jest-message-util requires #babel/code-frame. I do see #babel/code-frame in my node_modules though... so perhaps the problem is that jester is saying "ok, all instances of #, turn into public/js" ?
"#(.*)$": "<rootDir>/public/js/$1"
will convert #babel/code-frame to
"<rootDir>/public/js/babel/code-frame"
which doesn't exist. You need to make your pattern more specific and do
"#/(.*)$": "<rootDir>/public/js/$1"
Note the additional / at the beginning. That way it will still match your #/widgets/widget, but it won't match other scoped packages.

Extending multiple recommended configurations in ESLint

The Story:
Currently, we are extending the recommended ESLint configuration:
{
"extends": "eslint:recommended",
...
"plugins": [
"angular",
"jasmine",
"protractor"
],
"rules": {
"no-multiple-empty-lines": 2,
"no-trailing-spaces": 2,
"jasmine/valid-expect": 2
}
}
And also using angular, jasmine and protractor ESLint plugins which also ship with their own recommended configurations (default rule strictness levels and default rule parameters).
The Question:
How can we use all the recommended configurations at the same time - the one that ESLint and all the used plugins ship with?
Tried the following:
{
"extends": [
"eslint:recommended",
"plugin:protractor/recommended",
"plugin:jasmine/recommended",
"plugin:angular/recommended"
],
...
}
but got the following error:
Cannot read property 'recommended' of undefined
How can we use all the recommended configurations at the same time -
the one that ESLint and all the used plugins ship with?
Your syntax is correct, and multiple extensions are loaded like this:
{
"extends": [
"eslint:recommended",
"plugin:protractor/recommended",
"plugin:jasmine/recommended",
"plugin:angular/recommended"
]
}
However, this requires that the plugins in question actually come bundled with recommended settings. eslint-plugin-angular does not, and you have to install it yourself:
npm install --save-dev eslint-config-angular
Change your eslint settings to
{
"extends": [
"eslint:recommended",
"plugin:protractor/recommended",
"plugin:jasmine/recommended",
"angular"
]
}
and it should work.

How to use ESLint with Jest

I'm attempting to use the ESLint linter with the Jest testing framework.
Jest tests run with some globals like jest, which I'll need to tell the linter about; but the tricky thing is the directory structure, with Jest the tests are embedded with the source code in __tests__ folders, so the directory structure looks something like:
src
foo
foo.js
__tests__
fooTest.js
bar
bar.js
__tests__
barTest.js
Normally, I'd have all my tests under a single dir, and I could just add an .eslintrc file there to add the globals... but I certainly don't want to add a .eslintrc file to every single __test__ dir.
For now, I've just added the test globals to the global .eslintrc file, but since that means I could now reference jest in non-testing code, that doesn't seem like the "right" solution.
Is there a way to get eslint to apply rules based on some pattern based on the directory name, or something like that?
The docs show you are now able to add:
"env": {
"jest/globals": true
}
To your .eslintrc which will add all the jest related things to your environment, eliminating the linter errors/warnings.
You may need to include plugins: ["jest"] to your esconfig, and add the eslint-plugin-jest plugin if it still isn't working.
ESLint supports this as of version >= 4:
/*
.eslintrc.js
*/
const ERROR = 2;
const WARN = 1;
module.exports = {
extends: "eslint:recommended",
env: {
es6: true
},
overrides: [
{
files: [
"**/*.test.js"
],
env: {
jest: true // now **/*.test.js files' env has both es6 *and* jest
},
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
// "extends": ["plugin:jest/recommended"]
plugins: ["jest"],
rules: {
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error"
}
}
],
};
Here is a workaround (from another answer on here, vote it up!) for the "extend in overrides" limitation of eslint config :
overrides: [
Object.assign(
{
files: [ '**/*.test.js' ],
env: { jest: true },
plugins: [ 'jest' ],
},
require('eslint-plugin-jest').configs.recommended
)
]
From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724
You can also set the test env in your test file as follows:
/* eslint-env jest */
describe(() => {
/* ... */
})
To complete Zachary's answer, here is a workaround for the "extend in overrides" limitation of eslint config :
overrides: [
Object.assign(
{
files: [ '**/*.test.js' ],
env: { jest: true },
plugins: [ 'jest' ],
},
require('eslint-plugin-jest').configs.recommended
)
]
From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724
As of 2021, I think the correct way or at least the one that works is to install #types/jest and eslint-plugin-jest:
npm i -D eslint-plugin-jest #types/jest
And adding the Jest plugin into .eslintrc.js with the overrides instruction mentioned by #Loren:
module.exports = {
...
plugins: ["jest"],
...
overrides: [
{
files: ["**/*.test.js"],
env: { "jest/globals": true },
plugins: ["jest"],
extends: ["plugin:jest/recommended"],
},
],
...
};
This way you get linting errors in your source files as well as in test files, but in test files you don't get linting errors for test and other Jest's functions, but you will get them in your source files as they will appear as undefined there.
I solved the problem REF
Run
# For Yarn
yarn add eslint-plugin-jest -D
# For NPM
npm i eslint-plugin-jest -D
And then add in your .eslintrc file
{
"extends": ["airbnb","plugin:jest/recommended"],
}
some of the answers assume you have eslint-plugin-jest installed, however without needing to do that, you can simply do this in your .eslintrc file, add:
"globals": {
"jest": true,
}
First install eslint-plugin-jest
Running:
yarn add eslint-plugin-jest or npm install eslint-plugin-jest
Then edit .eslintrc.json
{
"env":{
"jest": true
}
}
As of ESLint V 6 (released in late 2019), you can use extends in the glob based config as follows:
"overrides": [
{
"files": ["*.test.js"],
"env": {
"jest": true
},
"plugins": ["jest"],
"extends": ["plugin:jest/recommended"]
}
]
Add environment only for __tests__ folder
You could add a .eslintrc.yml file in your __tests__ folders, that extends you basic configuration:
extends: <relative_path to .eslintrc>
env:
jest: true
If you have only one __tests__folder, this solution is the best since it scope jest environment only where it is needed.
Dealing with many test folders
If you have more test folders (OPs case), I'd still suggest to add those files. And if you have tons of those folders can add them with a simple zsh script:
#!/usr/bin/env zsh
for folder in **/__tests__/ ;do
count=$(($(tr -cd '/' <<< $folder | wc -c)))
echo $folder : $count
cat <<EOF > $folder.eslintrc.yml
extends: $(printf '../%.0s' {1..$count}).eslintrc
env:
jest: true
EOF
done
This script will look for __tests__ folders and add a .eslintrc.yml file with to configuration shown above. This script has to be launched within the folder containing your parent .eslintrc.
Pattern based configs are scheduled for 2.0.0 release of ESLint. For now, however, you will have to create two separate tasks (as mentioned in the comments). One for tests and one for the rest of the code and run both of them, while providing different .eslintrc files.
P.S. There's a jest environment coming in the next release of ESLint, it will register all of the necessary globals.
I got it running after spending some time trying out different options. Hope this helps anyone else getting stuck.
.eslintrc.json (in root project folder):
{
"env": {
"browser": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"standard",
"plugin:jest/all"
],
"parser": "#babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"jest/no-hooks": [
"error",
{
"allow": [
"afterEach",
"beforeEach"
]
}
]
},
"plugins": [
"jest"
]
}
Empty .babelrc (in root project folder):
{}
.package.json (in root project folder):
{
"scripts": {
"test": "jest",
"lint": "npx eslint --format=table .",
"lintfix": "npx eslint --fix ."
},
"devDependencies": {
"#babel/core": "^7.15.0",
"#babel/eslint-parser": "^7.15.0",
"aws-sdk-mock": "^5.2.1",
"eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.24.0",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"jest": "^27.0.6"
}
}
VS Code settings.xml (editor configuration: enables auto fix on save + babel parser):
"eslint.alwaysShowStatus": true,
"eslint.format.enable": true,
"eslint.lintTask.enable": true,
"eslint.options": {
"parser": "#babel/eslint-parser"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript"
]
In your .eslintignore file add the following value:
**/__tests__/
This should ignore all instances of the __tests__ directory and their children.

Categories