- Notifications
You must be signed in to change notification settings - Fork9
hopefully the last eslint config you'll ever need - customizable & modern best practices for JS, TS, Node, React, Remix, Next, Jest, testing-library & storybook
License
ljosberinn/eslint-config-galex
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
yarn add -D eslint-config-galex eslintnpm install --save-dev eslint-config-galex eslint
Usage with create-react-app
As of January 2021 / due to CRA v5, currently no additional steps are required! 🎉
Beginning witheslint-config-galex
v4.2.2
or newer, until this disclaimer is removed you need to install the following dependencies additionally:
"eslint-plugin-jest": "27.2.0"
npm i --save-dev eslint-plugin-jest@27.2.0yarn add -D eslint-plugin-jest@27.2.0
Beginning witheslint-config-galex
v4.5.0
or newer, until this disclaimer is removed you need to install the following dependencies additionally:
"eslint-plugin-react": "7.32.2"
"eslint-plugin-jsx-a11y": "6.7.1"
"eslint-plugin-import": "2.27.5"
npm i --save-dev eslint-plugin-react@7.32.2npm i --save-dev eslint-plugin-jsx-a11y@6.7.1npm i --save-dev eslint-plugin-import@2.27.5yarn add -D eslint-plugin-react@7.32.2yarn add -D eslint-plugin-jsx-a11y@6.7.1yarn add -D eslint-plugin-import@2.27.5
Usage with Next.js
In yournext.config.js
, I heavily recommend settingeslint.ignoreDuringBuilds
totrue
. Otherwise, you'll have to installeslint-config-next
separately and won't benefit of this config and your customization on top.
Usage with Remix Run
No additional setup is required! 🎉
You profit automatically of automatic dependency and feature detection. Due to the nature of ESLint configs however this approach is significantly harder to customize.
// .eslintrc.jsmodule.exports={extends:'galex',};
This showcases the required setup to begin with customizing your config on an advanced level. Please check out theExamples
section below for more details.
// .eslintrc.jsconst{ createConfig}=require('eslint-config-galex/dist/createConfig');module.exports=createConfig();
Incremental Adoption
// .eslintrc.jsconst{ createConfig}=require('eslint-config-galex/dist/createConfig');module.exports=createConfig({incrementalAdoption:true,});
Standalone Generation
By default,eslint-config-galex
reads yourpackage.json
as well as, if present,tsconfig.json
to determine feature availability. On weaker machines however, this turned out to be a performance bottleneck. Realistically, neither your dependencies nor your tsconfig changethat often.
To generate a static config based on yourcurrent dependencies & tsconfig, use:
nodenode_modules/eslint-config-galex/dist/generateStandalone
which will create a.eslintrc.json
in your root directory.
How do I pass settings forcreateConfig
to standalone generation?
Simple! Have aeslint-galex-settings.json
file in your root directory and it will be picked up.
An example would look like this:
// eslint-galex-settings.json (remove this comment as its invalid json){"incrementalAdoption":true}
Important: to keep this in sync with your dependencies, I recommend adding apostinstall
step to your scripts:
// package.json"scripts":{// other scripts"postinstall":"node node_modules/eslint-config-galex/dist/generateStandalone"}
Remember to re-run this command whenever you make feature-availability-relevant changes to yourtsconfig.json
as well, such asmodule
,target
orlib
.
History: prior to v4,eslint-config-galex
shipped with internal caching. Sadly, this prove to be both a maintenance overhead as well as not as useful as it initially promised to be for various reasons (e.g. VSCode ESLint apparently restarting the process when switching files which cachebusted due to a different process).
Starting with a blank slate
You like all the featureseslint-config-galex
ships with but you heavily disagree with many rule settings?
Say no more. Simply pass{ blankSlate: true }
tocreateConfig
and you still benefit from automatic dependency detection, the general override setup based on file patterns, butevery rule will be set tooff
.
This way, you can customize it entirely to your likings without having to create n overrides for rules and or rulesets.
Migrating a codebase to TypeScript
While in the process of migration, you may end up in a situation where you cannot turn oncompilerOptions.checkJs
from TypeScript itself due to e.g. builds breaking. However, by default certain rules will be disabled for JavaScript files because they are technically shadowed by TypeScript itself, e.g.no-undef
.
You can opt out of this behaviour by either:
- passing
enableJavaScriptSpecificRulesInTypeScriptProject
astrue
tocreateConfig
- enabling
compilerOptions.checkJs
once you're there
Example:
const{ createConfig}=require('eslint-config-galex/dist/createConfig');module.exports=createConfig({enableJavaScriptSpecificRulesInTypeScriptProject:true,});
Disabling a specific @typescript-eslint rule
const{ createConfig}=require('eslint-config-galex/dist/createConfig');const{ getDependencies}=require('eslint-config-galex/dist/getDependencies');const{ createTypeScriptOverride,}=require('eslint-config-galex/dist/overrides/typescript');constdependencies=getDependencies();constcustomTypescriptOverride=createTypeScriptOverride({ ...dependencies,rules:{// here goes anything that applies **exclusively** to typescript files based on the `files` glob pattern also exported from ../overrides/typescript'@typescript-eslint/explicit-module-boundary-types':'warn',// downgrading the default from "error" to "warn"},});module.exports=createConfig({overrides:[customTypescriptOverride],});
Changing a eslint-plugin-unicorn rule specifically for React files
const{ createConfig}=require('eslint-config-galex/dist/createConfig');const{ getDependencies}=require('eslint-config-galex/dist/getDependencies');const{ createReactOverride,}=require('eslint-config-galex/dist/overrides/react');constdependencies=getDependencies();constcustomReactOverride=createReactOverride({ ...dependencies,rules:{'unicorn/no-abusive-eslint-disable':'off',},});module.exports=createConfig({overrides:[customReactOverride],});
Adding plugins to any override
const{ createConfig}=require('eslint-config-galex/dist/createConfig');const{ getDependencies}=require('eslint-config-galex/dist/getDependencies');const{ createReactOverride,}=require('eslint-config-galex/dist/overrides/react');constdependencies=getDependencies();constcustomReactOverride=createReactOverride({ ...dependencies,plugins:['my-fancy-plugin'],rules:{'plugin/foo':'warn','plugin/bar':'error','plugin/baz':'off',},});module.exports=createConfig({overrides:[customReactOverride],});
Building your own config with the available exports
const{ getDependencies}=require('eslint-config-galex/dist/getDependencies');const{ files, parser, defaultSettings,}=require('eslint-config-galex/dist/overrides/react');constdependencies=getDependencies();constmyReactOverride={// using the internal react glob pattern files,// using the internal default react parser parser,// defining your custom rulesrules:{'react/react-in-jsx-scope':'warn',},// using the default settingssettings:defaultSettings,};module.exports={overrides:[myReactOverride],rules:{'no-await-in-loop':'warn',},};
Setting up ESLint can be easy.
Plug in someone's config or one of the many "industry standards" and be donewith it. Eventually you learn that some of those practices maybe aren't the bestidea. Too restrictive, treading into Prettier territory, conflicting with otherrules, too opinionated or even outdated, you name it. What to do?
You begin adding// eslint-disable-next-line rulename-here
. It works, butlitters the code.
You begin disabling rules altogether. Maybe because you don't know better, orbecause the rule is actually bad for your situation. You begin to wonder.
You check npm and see there are2.8k+ (August 2020)4.1k+ (December 2021)eslint-plugin-*
packagesout there. And even worse - 10k+eslint-config-*
packages. Which to choose?You sort by popularity and see some familiar faces. Time to install!
A few hours into stitching all those popular linting rules together you noticesome rules collide, some rules are outdated, some expect others to be disabled,but only circumstantially. Enough!
"Now is the time to finally read through all rulesets and decide which I want!"you scream out loud,"it can't be that many!" - but find yourself finishing thefirst repo after 6 hours.
Setting up ESLintproperly wasn't that easy after all.
Couldn't this be easier?
It's incrementally adoptable! Usually you pick a config at one point in time:when starting a fresh project, or at least early on. Migrating later on,especially when working in teams with lots of code movement, you'd run intomerging conflicts real quick.
Good news: you can use
createConfig({ incrementalAdoption: true })
todowngrade all errors to warnings, and disable all warnings!This allows you to introduce the config at an arbitrary point in time, whilestill profiting of it from minute one and still allows you to continue. Mosturgent issues won't break the build - the best of both worlds!
Once you feel comfortable raising the reporting level, simply set
incrementalAdoption
to false or remove it from the arguments passed tocreateConfig
.Integration tests for all cases.
All internals, literally everything, is re-exported. Don't like somedecision? Rules too weak? Want to add custom rules? Everything is covered!
This hopefully prevents the need of having to migrate between configs everyonce in a while which builds up frustration due to misconfiguration and theentire overhead related to that. Dependency injection, just for an eslintconfig!
This config has aheavy focus on code quality, best practices andtries to omit opinions.
Everything is dynamically included based on yourpackage.json
and when using TypeScript, yourtsconfig.json
.Rules are selectively applied based on file name patterns.
All rules are commented and link to their docs.
- React
- Next.js
- Remix Run
- TypeScript
- Node.js
- jest
- jest-dom
- @testing-library
- prettier
- storybook & storybook/testing-library
- NestJS (with TypeScript)
All rulesets and overrides are created through functions accepting an objectmatching this schema:
interfaceProject{/** * whether `jest` is present */hasJest:boolean;/** * whether `@testing-library/jest-dom` is present */hasJestDom:boolean;/** * whether `@types/node` is present */hasNodeTypes:boolean;/** * whether any `@testing-library/<environment>` is present */hasTestingLibrary:boolean;/** * whether `@nestjs/core` is present */hasNest:boolean;storybook:{/** * whether any `@storybook/` is present that is not `@storybook/testing-library` */hasStorybook:boolean;/** * whether `@storybook/testing-library` is present */hasStorybookTestingLibrary:boolean;};typescript:{/** * whether `typescript` is present */hasTypeScript:boolean;/** * the installed version */version:string;/** * your tsConfig; used to detect feature availability */config?:object;};react:{/** * whether any flavour of react is present */hasReact:boolean;/** * whether `next` is present */isNext:boolean;/** * whether `@remix-run/react` is present */isRemix:boolean;/** * whether `preact` is present * currently without effect */isPreact:boolean;/** * the installed version */version:string;/** * whether the project was bootstrapped with create-react-app */isCreateReactApp:boolean;};/** * your custom rules on top */rules?:object;}
This list only mentions the exports most people will need. For an exhaustivelist, check out the source.
const { createTypeScriptOverride } = require('eslint-config-galex/dist/overrides/typescript')
const { createReactOverride } = require('eslint-config-galex/dist/overrides/react')
const { createJestOverride } = require('eslint-config-galex/dist/overrides/jest')
const { createStorybookOverride } = require('eslint-config-galex/dist/overrides/storybook')
Please note that the test override should always come last.
const { createEslintCoreRules } = require('eslint-config-galex/dist/plugins/eslint-core')
const { createImportRules } = require('eslint-config-galex/dist/plugins/import')
const { createNextJsRules } = require('eslint-config-galex/dist/plugins/next')
const { createPromiseRules } = require('eslint-config-galex/dist/plugins/promise')
const { createSonarjsRules } = require('eslint-config-galex/dist/plugins/sonarjs')
const { createUnicornRules } = require('eslint-config-galex/dist/plugins/unicorn')
const{ createConfig}=require('eslint-config-galex/dist/createConfig');const{ createTypeScriptOverride,}=require('eslint-config-galex/dist/overrides/typescript');constpackageJson=require('./package.json');// since `createTypeScriptOverride` is entirely configurable, we need to inform it about its environmentconsttsOverrideConfig={react:{hasReact:true,},rules:{'@typescript-eslint/ban-ts-comment':'off',},typescript:{hasTypeScript:true,// sync with package.json should you upgrade TSversion:packageJson.dependencies.typescript,},};// solely an override for TSconsttsOverride=createTypeScriptOverride(tsOverrideConfig);// pass it into createConfig as array as it will be merged with the other overridesmodule.exports=createConfig({overrides:[tsOverride]});
const{ createConfig}=require('eslint-config-galex/dist/createConfig');const{ getDependencies}=require('eslint-config-galex/dist/getDependencies');const{ createJestOverride,}=require('eslint-config-galex/dist/overrides/jest');/** * override to enable jest globals for `/testUtils` folder */constcustomJestLikeOverride=createJestOverride({ ...getDependencies(),files:['testUtils/*.ts?(x)'],});module.exports=createConfig({overrides:[customJestLikeOverride],});
This project follows semver.
About
hopefully the last eslint config you'll ever need - customizable & modern best practices for JS, TS, Node, React, Remix, Next, Jest, testing-library & storybook
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Contributors10
Uh oh!
There was an error while loading.Please reload this page.