yarn add -D eslint-config-galex eslint
npm install --save-dev eslint-config-galex eslint
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.js
module.exports = {
extends: 'galex',
};
This showcases the required setup to begin with customizing your config on an advanced level. Please check out the Examples
section below for more details.
// .eslintrc.js
const { createConfig } = require('eslint-config-galex/dist/createConfig');
module.exports = createConfig();
Setting up ESLint can be easy.
Plug in someone's config or one of the many "industry standards" and be done with it. Eventually you learn that some of those practices maybe aren't the best idea. Too restrictive, treading into Prettier territory, conflicting with other rules, too opinionated or even outdated, you name it. What to do?
You begin adding // eslint-disable-next-line rulename-here
. It works, but
litters the code.
You begin disabling rules altogether. Maybe because you don't know better, or because the rule is actually bad for your situation. You begin to wonder.
You check npm and see there are 2.8k+ (August 2020) 4.1k+ (December 2021) eslint-plugin-*
packages
out 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 notice some 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 the first repo after 6 hours.
Setting up ESLint properly 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 into merging conflicts real quick.
Good news: you can use createConfig({ incrementalAdoption: true })
to
downgrade all errors to warnings, and disable all warnings!
This allows you to introduce the config at an arbitrary point in time, while still profiting of it from minute one and still allows you to continue. Most urgent 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 to
createConfig
.
Integration tests for all cases.
All internals, literally everything, is re-exported. Don't like some decision? Rules too weak? Want to add custom rules? Everything is covered!
This hopefully prevents the need of having to migrate between configs every once in a while which builds up frustration due to misconfiguration and the entire overhead related to that. Dependency injection, just for an eslint config!
This config has a heavy focus on code quality, best practices and tries to omit opinions.
Everything is dynamically included based on your package.json
and when using TypeScript, your tsconfig.json
.
Rules are selectively applied based on file name patterns.
All rules are commented and link to their docs.
All rulesets and overrides are created through functions accepting an object matching this schema:
interface Project {
/**
* 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 exhaustive list, 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');
const packageJson = require('./package.json');
// since `createTypeScriptOverride` is entirely configurable, we need to inform it about its environment
const tsOverrideConfig = {
react: {
hasReact: true,
},
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
},
typescript: {
hasTypeScript: true,
// sync with package.json should you upgrade TS
version: packageJson.dependencies.typescript,
},
};
// solely an override for TS
const tsOverride = createTypeScriptOverride(tsOverrideConfig);
// pass it into createConfig as array as it will be merged with the other overrides
module.exports = createConfig({ overrides: [tsOverride] });
files
: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
*/
const customJestLikeOverride = createJestOverride({
...getDependencies(),
files: ['testUtils/*.ts?(x)'],
});
module.exports = createConfig({
overrides: [customJestLikeOverride],
});
This project follows semver.