A simple ESLint configuration for JavaScript, TypeScript, and React projects.
Uses @eslint/js, @stylistic/eslint-plugin, typescript-eslint, @eslint-react/eslint-plugin, and eslint-plugin-react-hooks configurations.
Written in TypeScript and transpiles to JavaScript (ESM).
I noticed I was duplicating much of the ESLint configuration between my projects, and synchronizing changes was annoying. So I have extracted the configuration into a new package to use anywhere.
You are welcome to use this configuration, but it is primarily designed for my personal use. I cannot promise to support your use case. However, I do plan to follow semantic versioning for handling breaking changes.
You must also install eslint to use this package.
npm install --save-dev eslint @jstnmcbrd/eslint-configAdd a script in your package.json for linting.
{
"scripts": {
"lint": "eslint"
}
}Add a eslint.config.js file and import the configuration as follows.
import eslintConfig from '@jstnmcbrd/eslint-config';
export default eslintConfig();import eslintConfig from '@jstnmcbrd/eslint-config';
export default eslintConfig({ react: true });import eslintConfig from '@jstnmcbrd/eslint-config';
export default eslintConfig({ typescript: true });This configuration assumes that your build output directory is dist and ignores all files in that directory.
It also uses the projectService feature from typescript-eslint for typed linting. Therefore, all linted files must be included in your project's root tsconfig.json.
It is generally good practice to include all JavaScript-related files that need type information in the root tsconfig.json, for consistency and improved IDE integration.
If you need to exclude some files from your typescript build (like configs or test files), make a tsconfig.build.json file that extends from tsconfig.json and only includes files you want to build.
For an example, see this project's tsconfig.json and tsconfig.build.json files.
import eslintConfig from '@jstnmcbrd/eslint-config';
export default eslintConfig({ react: true, typescript: true });If you need to extend the config, you can use the defineConfig helper from eslint.
For example, you could add NodeJS globals (for a non-TypeScript project).
import eslintConfig from '@jstnmcbrd/eslint-config';
import { defineConfig } from 'eslint/config';
import { nodeBuiltin } from 'globals';
export default defineConfig(
eslintConfig(),
{
languageOptions: {
globals: nodeBuiltin,
},
},
);Or you could ignore a directory.
import eslintConfig from '@jstnmcbrd/eslint-config';
import { defineConfig, globalIgnores } from 'eslint/config';
export default defineConfig(
eslintConfig(),
globalIgnores(['tmp']),
);- Only compatible with ESLint v9
- Uses the new ESLint flat config
- No support for the legacy config, so consider upgrading!
- Transpiled by TypeScript to ECMAScript with ES modules
- No support for CommonJS, so consider upgrading!
- This means you cannot import the package from a node project that is not using
"type":"module"
- Uses as few plugins as possible
- Uses plugins that are as official as possible, and avoids more esoteric/niche plugins
- Stays as close to recommended defaults as possible, with a few noteable exceptions
- Tabs instead of spaces
- Semicolons
- Does not use Prettier
- It's good to be standardized and opinionated, but I find Prettier to be inflexible to the point of dogmatism. I created this package to enforce my own dogmatic opinions instead.
- There's an interesting debate between the purposes of formatters and linters. Strict formatters often erase context encoded in code style, so flexibility can be useful for retaining the intent of the programmer.
- For another perspective, see Anthony Fu's blog post on the subject.
This project aspires to abide by semantic versioning. However, given the interesting nature of updating code quality rules, it is not always clear what constitutes a "breaking" change. ESLint has a section on the subject in their README.
When I update a rule in a way that could cause a few harmless lint errors, I will try to always bump a minor version. If I update many rules, fundamentally change a rule, or change the configuration API, I will bump a major version.
This project abides by keep-a-changelog. All relevant changes will be documented in the CHANGELOG.