Recently, the eslint-config-prettier v8 upgrade broke my ESLint configuration, and I realized I needed a centralized way of managing my ESLint configuration across projects.
This is the outline for how I will solve common configuration across projects going forward. Here are the key features:
- Layer your ESLint rules based on topics: ESLint + Prettier, then TypeScript, then React/Vue.
- Use Lerna to publish scoped packages to npmjs.
- Some helper tools to upgrade your code.
Disclaimer: This is not my original work, but leveraged from other's work, most notably:
- The ESLint configuration started with ntnyq configs
- The TypeScript idea came from unlikelystudio settings
The benefit of this organizational structure is layering your ESLint rules. Some rules apply for TypeScript projects. Some for TypeScript/React projects. What if you add Prettier to the mix?
A picture is worth a 1000 words:
Each rule layers parent rules into it's rules. For example:
eslint-config-prettier-typescript-react
:
extends: [
'@YOUR_SCOPE/typescript-react',
'@YOUR_SCOPE/prettier-react',
'@YOUR_SCOPE/prettier-typescript',
...
which in turn eslint-config-prettier-typescript
:
extends: [
'@YOUR_SCOPE/typescript',
'@YOUR_SCOPE/prettier',
...
etc.
Naturally, when you publish your configs, they will reference your scope, not @YOUR_SCOPE 😄.
- Choose your NPM scope.
- If you use your npm username, you can it as your scope
- If you want a different scope, you must login to npmjs.com and add an organization to your account
- Globally search/replace all occurrences of
@YOUR_SCOPE
and replace with your scope - Globally search/replace all occurrences of
YOUR_SCOPE
and replace with your username - Rename
packages/mrm-preset-YOUR_SCOPE
to match your scope (without the@
) - Login to NPM using
npm login
- Publish your packages using
lerna publish
mrm is a fantastic tool for updating projects. Their tagline is:
Codemods for your project config files
I'm a huge fan of this project. It allows me to script intelligent updates to my configs based on set criteria. For example, in the configs
preset (explained below), it does:
const parts = []
if (hasPrettier) parts.push('prettier')
if (hasTypescript) parts.push('typescript')
if (hasVue) parts.push('vue')
else if (hasReact) parts.push('react')
const base = parts.length ? '-' + parts.join('-') : ''
const full = `${configScope}/eslint-config${base}`
const eslintPreset = `${configScope}/${base.slice(1)}`
So, by package.json
inspection, it determines which preset you most likely want, and updates the config to match that preset. Very cool.
A Preset is a way for you to customize MRM behavior. Included is a custom preset for your own use where you can put your upgrades as you use MRM. In this preset I have 2 tasks:
- configs: Migrate configs of a project to this structure
- typescript: Migrate your
tsconfig.json
to this structure (yes, this should probably be part of theconfigs
preset, but it was easier to simply tweak the existing MRMtypescript
task)
To use these, follow these steps:
- Publish your preset per instructions above
- Install your preset globally with
npm i -g mrm-preset-YOURSCOPE
- Change into a project you want to upgrade
- Make sure you have committed all your changes and your git tree is clean
- Run
mrm eslint
- If you use Prettier, run
mrm prettier
- (these two command setup eslint/prettier in a standard way -- the next step really needs
.eslintrc.json
instead of a .js file)
- (these two command setup eslint/prettier in a standard way -- the next step really needs
- Run
mrm --preset YOURSCOPE config
Once that finishes, you can evaluate the proposed changes and see if you like the results. If they are satisfactory, commit them and enjoy the new config. If they are not, do a
git reset --hard HEAD
and update your preset at
packages/mrm-preset-YOUR_SCOPE/configs/index.js
as needed to modify the configs as you see fit.
Enjoy!