A modular ESLint config used at Wise.
-
Install the package as a dev dependency along with ESLint:
pnpm add --save-dev @wise/eslint-config
Consumers needn’t install any other dependencies, thanks to using
@rushstack/eslint-patch
under the hood. -
Extend your ESLint configuration as follows:
// .eslintrc.json { "root": true, "extends": [ /* Recommended for all projects, includes TypeScript rules */ "@wise/eslint-config/base-strict", // `-strict` may be omitted /* Uncomment lines in the order below as you adopt each technology */ // "@wise/eslint-config/react", // "@wise/eslint-config/next", // "@wise/eslint-config/jest", // "@wise/eslint-config/testing-library-react", // "@wise/eslint-config/cypress", // "@wise/eslint-config/storybook", ], }
-
If you’re using a monorepo with TypeScript, please set
parserOptions.project
as per the docs of typescript-eslint.
Set up your package.json scripts to run the linting on the CLI. We recommend adhering to ESLint’s package.json conventions for naming scripts.
// package.json
{
"scripts": {
/* TypeScript-specific logic may be enabled as hinted by comments below */
"lint": "pnpm run lint:js+ts && pnpm run lint:format", // && pnpm run lint:types
"lint:js+ts": "eslint --ext .js,.jsx,.mjs,.cjs,.ts,.tsx,.mts,.cts --ignore-path .gitignore .",
"lint:format": "prettier \"**/*\" --check --ignore-unknown",
// "lint:types": "tsc --noEmit",
"lint:fix": "pnpm run lint:fix:js+ts && pnpm run lint:fix:format",
"lint:fix:js+ts": "pnpm run lint:js+ts --fix",
"lint:fix:format": "prettier \"**/*\" --write --ignore-unknown",
},
}
Stylistic linting rules which may conflict with Prettier are turned off.
We encourage developers to use Prettier’s opinionated defaults with no additional configuration.
-
Install packages as follows:
pnpm add --save-dev husky nano-staged
-
Configure scripts to be run on staged files:
// package.json "nano-staged": { "*": "prettier --write --ignore-unknown", "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": "eslint --fix", }
-
Configure git hooks via Husky:
pnpm exec husky echo "pnpm exec nano-staged" > .husky/pre-commit npm pkg set scripts.prepare="husky || cd ."
The
|| cd .
part sets the exit code to zero in a cross-platform manner whenhusky
isn’t found, e.g. whendevDependencies
aren’t installed.
Extend your editor configuration as follows:
// .vscode/settings.json
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
},
}
If you think a rule should be added or changed, please create a pull request. Releases are managed via Changesets and follow Semantic Versioning conventions.
Rules of our configs shouldn’t be turned off or overridden in general. When encountering a false-positive, please disable it via eslint-disable-next-line
or eslint-disable
and consider filing an issue to the Web Guild.
The first time you integrate with the config, you might get a lot of import issues.
1:1 warning Run autofix to sort these imports! simple-import-sort/imports
This error is auto-fixable using the --fix
option.
When trying to import from a .d.ts
file, import type
should be used over import
, e.g.:
- import { AlertType } from "@transferwise/components/build/types/alert/Alert";
+ import type { AlertType } from "@transferwise/components/build/types/alert/Alert";
Furthermore, setting verbatimModuleSyntax
in TSConfig is recommended to avoid these issues and deal with side-effects explicitly.
When using multiple configuration files in tsconfig.json
, e.g. extends: ["array", "of", "tsconfigs"]
, the following error may occur:
TypeError: The "path" argument must be of type string. Received an instance of Array
This happens because eslint-import-resolver-typescript doesn’t support the array extends
syntax introduced by TypeScript 5.
Please don’t extend from multiple TSConfigs at this time.
When linting JavaScript without types, the following error may occur:
You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously
This happens if your Babel configuration uses ECMAScript module syntax. By migrating to JSON or using CommonJS, the issue can be mitigated, e.g.:
// babel.config.js
- export default { /* … */ };
+ module.exports = { /* … */ };
Sometimes, if you integrate, you might see an error similar to this
Oops! Something went wrong! :(
ESLint: 8.25.0
ESLint couldn't determine the plugin "react" uniquely.
- /Users/paul.ang/tw-code/cards-page/node_modules/.pnpm/eslint-plugin-react@7.31.10_eslint@8.25.0/node_modules/eslint-plugin-react/index.js (loaded in ".eslintrc.js » plugin:react/jsx-runtime")
- /Users/paul.ang/tw-code/cards-page/node_modules/.pnpm/@wise+eslint-config@8.0.1_@babel+plugin-sy_afooenpggdpbpvboeoaxgxg2zu/node_modules/@wise/eslint-config/node_modules/eslint-plugin-react/index.js (loaded in ".eslintrc.js » @wise/eslint-config » plugin:react/jsx-runtime")
Please remove the "plugins" setting from either config or remove either plugin installation.
If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
Most of the time, removing the offending plugin (in this case, plugin:react/jsx-runtime
) in your eslintrc
file should solve the issue.
What this means is that the said plugin is already imported in the configs. Importing them again will cause the issue.