I have a project where there is a top-level .eslintrc.json
and another config inside a subdirectory. When I open a file located in that subdirectory, VSCode complains that ESLint can’t find Babel config:
Parsing error: No Babel config file detected for path/to/files.jsx. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files.
But I do have .babelrc
in both directories next to .eslintrc.json
.
Here is my subdir configuration:
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": false
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2018,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"settings": {
"react": {
"version": "detect"
}
},
"plugins": [
"react"
],
"extends": [
"plugin:react/recommended"
],
"rules": {
"indent": ["warn", 4, {"SwitchCase": 1}],
"brace-style": ["error", "1tbs"],
"semi": ["error", "always"],
"curly": ["error", "all"],
"arrow-parens": ["error", "as-needed"],
"comma-dangle": ["warn", "only-multiline"],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"arrow-spacing": ["error", {
"before": true,
"after": true
}],
"keyword-spacing": ["error", {
"before": true,
"after": true
}],
"constructor-super": "warn",
"valid-typeof": "warn",
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-undefined": "error",
"no-undef-init": "error",
"no-unreachable": "warn",
"no-unused-vars": ["warn", { "vars": "all", "args": "none"}],
"no-invalid-regexp": "error",
"no-multi-spaces": "warn",
"no-multiple-empty-lines": ["warn", {"max": 1}],
"react/prop-types": ["error", {"ignore": ["children"]}],
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/button-has-type": "warn",
"react/no-typos": "error",
"react/no-array-index-key": "warn",
"react/no-unused-state": "warn",
"react/no-unused-prop-types": "warn",
"react/self-closing-comp": "warn",
"react/sort-comp": ["error", {
"order": [
"static-methods",
"instance-variables",
"lifecycle",
"everything-else",
"render"
]
}],
"react/void-dom-elements-no-children": "error",
"react/jsx-pascal-case": "error",
"react/jsx-props-no-multi-spaces": "warn",
"react/jsx-tag-spacing": ["warn", {
"closingSlash": "never",
"beforeSelfClosing": "never",
"afterOpening": "never",
"beforeClosing": "allow"
}]
}
}
Top-level config:
{
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2018
},
"rules": {
"indent": ["warn", 4, {"SwitchCase": 1}],
"brace-style": ["error", "1tbs"],
"semi": ["error", "always"],
"curly": ["error", "all"],
"arrow-parens": ["error", "as-needed"],
"comma-dangle": ["warn", "only-multiline"],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"arrow-spacing": ["error", {
"before": true,
"after": true
}],
"keyword-spacing": ["error", {
"before": true,
"after": true
}],
"constructor-super": "warn",
"valid-typeof": "warn",
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-undefined": "error",
"no-undef-init": "error",
"no-unreachable": "warn",
"no-unused-vars": ["warn", { "vars": "all", "args": "none"}],
"no-invalid-regexp": "error",
"no-multi-spaces": "warn",
"no-multiple-empty-lines": ["warn", {"max": 1}]
}
}
Some members in my team this week wanted to make use of Private class fields in a NodeJS server. This proposal is currently shipped in Chrome, Edge, Firefox and NodeJS, with Safari notably absent. In this instance, we wanted to get them working for a backend server application, so support since Node 12, we’re good to go, or so I thought, turns out linters aren’t always here to save you time.
I summed my feelings on the whole process of figuring this out on Twitter.
Man trying to configure eslint to understand private class fields is a fucking hellscape
14:27 PM — 01 Dec 2020
Feel free if you want to skip ahead past the story, and to head right to Configuring ESLint.
For this article, i’ll be using this code example of using Private class fields, the code used is irrelevant.
export class Animal {
// this is a private class field!
#noise = '';
constructor(noise) {
this.#noise = noise;
}
makeNoise() {
console.log(this.#noise);
}
}
Enter fullscreen mode
Exit fullscreen mode
The first issue we hit when writing this new code, was of course, the linter started failing, so off to Google we went!
Struggling to finding a solution
A quick search for: eslint private class fields
you will most likely end up in this Stack Overflow issue.
It will tell you that ESLint does not support experimental stage 3 features, which is indeed correct, and to:
npm install eslint babel-eslint --save-dev
Enter fullscreen mode
Exit fullscreen mode
and to update your ESLint config file over to use:
"parser": "babel-eslint",
Enter fullscreen mode
Exit fullscreen mode
Sadly, it seems this is not an entire solution, it seems to make a couple of assumptions:
- You have babel-core installed
- You have a babel configuration file set up that knows how to transform code with a preset.
- Its possible that when the answer was posted
babel-eslint
did indeed solve al the problems.
If you are in a NodeJS server module, a lot of these assumptions are probably not met.
If you are a developer that has never had to use Babel because you work on the backend or on a build-less frontend, all this stuff can get daunting very fast.
Additionally, it seems since this answer was posted, things have moved on and the recommended parser
now lives at:
"parser": "@babel/eslint-parser",
Enter fullscreen mode
Exit fullscreen mode
The ESLint website does have some information about the Past, Present and Future of the babel-eslint over on its website.
Finding this information out was a bit of an adventure, and even on the official babel or ESLint website, it’s super unclear that you need to set up a babel config, and then still, what to put in it. I’m pretty sure the only reason I managed to figure it out in the end was because i’m familiar with the mess that is configuring Webpack, Jest and Babel.
Configuring ESLint
Let’s get our new syntax working!
First off, lets do the npm install
dance:
npm i eslint @babel/core @babel/eslint-parser @babel/preset-env -D
Enter fullscreen mode
Exit fullscreen mode
It’s nice to set up a linter task in your package json so you can run npm run lint
"scripts": {
"lint": "eslint ./"
},
Enter fullscreen mode
Exit fullscreen mode
I’m opting to use @babel/preset-env
because it has an easy way to enabled proposals that are shipped
in Browsers/Node. Other presets/plugins are available.
Next we need to construct an .eslintrc
file.
You can generate one using: ./node_modules/.bin/eslint --init
or just copy this starter:
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
}
}
Enter fullscreen mode
Exit fullscreen mode
Now if you run npm run lint
You will hit the following error:
/path/to/code/Animal.js
0:0 error Parsing error: No Babel config file detected for /path/to/code/Animal.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files
✖ 1 problem (1 error, 0 warnings)
Enter fullscreen mode
Exit fullscreen mode
It’s telling you we need to configure babel for @babel/eslint-parser
to work.
Lets set up a babel config file.
Create a file called .babelrc
and populate it with:
{
"presets": [
["@babel/preset-env"]
]
}
Enter fullscreen mode
Exit fullscreen mode
You can read about @babel/preset-env
on the Babel website.
Now if you run npm run lint
again you will hit the final error:
/path/to/code/Animal.js
2:4 error Parsing error: /path/to/code/Animal.js: Support for the experimental syntax 'classPrivateProperties' isn't currently enabled (2:5):
1 | export class Animal {
> 2 | #noise = '';
| ^
3 |
4 | constructor(noise) {
5 | this.#noise = noise;
Add @babel/plugin-proposal-class-properties (https://git.io/vb4SL) to the 'plugins' section of your Babel config to enable transformation.
If you want to leave it as-is, add @babel/plugin-syntax-class-properties (https://git.io/vb4yQ) to the 'plugins' section to enable parsing
✖ 1 problem (1 error, 0 warnings)
Enter fullscreen mode
Exit fullscreen mode
You could proceed to add plugins for each of the proposals as the instructions say, alternatively you can opt to say
I want all shipped proposals
.
To do this change your .babelrc
over to:
{
"presets": [
["@babel/preset-env",
{
"shippedProposals": true
}]
]
}
Enter fullscreen mode
Exit fullscreen mode
From the Babel docs: «set the shippedProposals option to true. This will enable polyfills and transforms for proposal which have already been shipped in browsers for a while.»
If you are using Jest
If you are using Jest, it will automatically pick up .babelrc
files, this might be problematic, as it will very helpfully start to try to transpile things like async/await
, potentially leading you down even more rabbit holes. With really helpful messages like:
ReferenceError: regeneratorRuntime is not defined
Enter fullscreen mode
Exit fullscreen mode
By dumb luck, i’ve been through the pain of this message many times, and knew exactly what was wrong, Jest was trying to transform the perfectly valid code.
It’s almost 2021, and this is a server app, I certainly do not want to transpile async/await
especially not in unit tests!
One way to work around this is to use a non-standard name for your .babelrc
file e.g. .babel-eslintrc
. There may be better solutions, but I certainly don’t want Jest unnecessarily transforming code.
In your .eslintrc
file you can update babelOptions
to use a custom configFile
"babelOptions": {
"configFile": "./.babel-eslintrc"
}
Enter fullscreen mode
Exit fullscreen mode
And there we go, Jest is now happy again because it’s not using the Babel configuration.
Summary
All in all this was a lot harder than I thought it would be, my guess is that many people don’t hit this issue because they happen to already have Babel configured. But in the case of backend dev, getting along happily, just trying to make use of a shipped JavaScript feature in a server, you can get dragged into the hellscape of frontend development tooling, and no one has fun there.
I hope this was a good read, if you feel like reading more of my work, please follow me on Twitter @griffadev, or get me a coffee if you feel like it ☕.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.