Skip to content

Commit

Permalink
move configs back to individual packages
Browse files Browse the repository at this point in the history
  • Loading branch information
bsokol-wl committed May 9, 2024
1 parent 565bb69 commit 9c5b87b
Show file tree
Hide file tree
Showing 14 changed files with 8,562 additions and 6,178 deletions.
77 changes: 45 additions & 32 deletions docs/eslint/flat-config-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,65 +98,78 @@ const config = [
export default config;
```

You can now delete your previous `.eslintrc` config file, as well as your `.eslintignore` file, if you have one. Please refer to the [official migration guide](https://eslint.org/docs/latest/use/configure/migration-guide) for more details.

## Example monorepo setup

Monorepo setups can be more complex, because each package should have its own ESLint config file.
Monorepo setups can be more complex, because each package should have its own ESLint rules. With flat config, ESLint will use which ever `eslint.config.js` is the first to be found by traversing up from the directory in which the `eslint` command was run. This means that, by default, individual ESLint configs within monorepo packages will be ignored if ESLint is run from the root directory.

### Top level
We can mimic the old ESLint behavior by importing each package's ESLint config into the top level and merging them together.

Create a new `eslint.config.js` at the root of your project. Import the monorepo workspace config. Ignore the directory or directories that contain your monorepo packages (and any other files you don't want linted).
### Monorepo packages

Inside each monorepo package, create a `eslint.config.js` file. Add the config module that matches the package type. For example, a web application would use the `webApplication` config, while a component libary would use the `reactLibrary` config:
```javascript
import workleapPlugin from "@workleap/eslint-config";

const config = [
{
ignores: ["node_modules/", "packages/"]
},
...workleapPlugin.configs.monorepoWorkspace
];
const config = workleapPlugin.configs.reactLibrary;

export default config;
```

### Monorepo packages

Inside each monorepo package, create another `eslint.config.js` file. Add the config module that matches the package type. For example, a web application would use the `webApplication` config, while a component libary would use the `reactLibrary` config:
You can also set custom ignore rules:
```javascript
import workleapPlugin from "@workleap/eslint-config";

const config = [
...workleapPlugin.configs.reactLibrary
...workleapPlugin.configs.reactLibrary,
ignores: ["build/"]
];

export default config;
```

You must run ESLint from each monorepo package. It will use which ever `eslint.config.js` is the first to be found by traversing up from the directory in which the `eslint` command was run. pnpm can be used to automate this process.
### Top level

You can now delete your previous `.eslintrc` config file, as well as your `.eslintignore` file, if you have one. Please refer to the [official migration guide](https://eslint.org/docs/latest/use/configure/migration-guide) for more details.
Create a new `eslint.config.js` at the root of your project. Import the monorepo workspace config.

In order to make it easier to scope config files to monorepo packages, we recommend using [eslint-flat-config-utils](https://github.com/antfu/eslint-flat-config-utils). The `concat` function makes it easier to join multiple configs together. Wrap your configuration objects in the `concat` function because it will automatically merege arrays.

### Running ESLint in the monorepo
```javascript
import { concat } from "eslint-flat-config-utils";
import workleapPlugin from "@workleap/eslint-config";

Ensure these 3 scripts are present in your top-level `package.json`:
```json
"scripts": {
"lint": "pnpm run \"/^lint:.*/\"",
"lint:eslint": "eslint . --max-warnings=0 --cache --cache-location node_modules/.cache/eslint",
"lint:eslint-packages": "pnpm -r --parallel --if-present --aggregate-output lint:eslint",
}
const config = concat(
{
ignores: ["node_modules/"]
},
workleapPlugin.configs.monorepoWorkspace
);

export default config;
```
- The `lint` script will run all scripts that start with "lint:" inside this `package.json`.
- `lint:eslint` will run ESLint at the top level of the project. You can set up your ESLint flags however you like.
- `lint:eslint-packages` will simulataneously run the `lint:eslint` script within each package's `package.json` if it has been defined.

Import each package's `eslint.config.js` and add them to the `concat` function. Wrap each of the package imports with the `extend` function, and provide the relative path to the root of each package. This will scope the files of that config to the given directory, including any ignores.

```javascript
import { concat } from "eslint-flat-config-utils";
import workleapPlugin from "@workleap/eslint-config";
import packageOneConfig from "./packages/one";
import packageTwoConfig from "./packages/two";

Add this script to the `package.json` of each monorepo package:
```json
"scripts": {
"lint:eslint": "eslint . --max-warnings=0 --cache --cache-location .cache/eslint"
}
const config = concat(
{
ignores: ["node_modules/"]
},
workleapPlugin.configs.monorepoWorkspace,
extend(packageOneConfig, "packages/one/"),
extend(packageTwoConfig, "packages/two/"),
);

export default config;
```
Now, whenever you run `pnpm lint` at the root level, each monorepo package will also execute their `lint:eslint` commands. We recommend using ESLint's cache feature, as shown in the example. Make sure you add the cache location to the `.gitignore` file.

With this setup, you can lint the entire project from the root, or from within each individual package directory.

## Advanced Configuration

Expand Down
32 changes: 20 additions & 12 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import workleapPlugin from "@workleap/eslint-plugin";
import { concat, extend } from "eslint-flat-config-utils";
import packageBrowserslistConfig from "./packages/browserslist-config/eslint.config.mjs";
import packageEslintPlugin from "./packages/eslint-plugin/eslint.config.js";
import packagePostcssConfigs from "./packages/postcss-configs/eslint.config.js";
import packageStylelintConfigs from "./packages/stylelint-configs/eslint.config.mjs";
import packageSwcConfigs from "./packages/swc-configs/eslint.config.mjs";
import packageTsupConfigs from "./packages/tsup-configs/eslint.config.mjs";
import packageWebpackConfigs from "./packages/webpack-configs/eslint.config.js";
import sampleApp from "./sample/app/eslint.config.js";
import sampleComponents from "./sample/components/eslint.config.js";
import sampleUtils from "./sample/utils/eslint.config.js";

const config = concat(
{
Expand All @@ -13,18 +23,16 @@ const config = concat(
]
},
workleapPlugin.configs.monorepoWorkspace,
extend(workleapPlugin.configs.typescriptLibrary, "packages/browserslist-config/"),
extend(workleapPlugin.configs.typescriptLibrary, {
ignores: ["lib/plugins.d.ts"]
}, "packages/eslint-plugin/"),
extend(workleapPlugin.configs.typescriptLibrary, "packages/postcss-configs/"),
extend(workleapPlugin.configs.typescriptLibrary, "packages/stylelint-configs/"),
extend(workleapPlugin.configs.typescriptLibrary, "packages/swc-configs/"),
extend(workleapPlugin.configs.typescriptLibrary, "packages/tsup-configs/"),
extend(workleapPlugin.configs.typescriptLibrary, "packages/webpack-configs/"),
extend(workleapPlugin.configs.webApplication, "sample/app/"),
extend(workleapPlugin.configs.reactLibrary, "sample/components/"),
extend(workleapPlugin.configs.typescriptLibrary, "sample/utils/")
extend(packageBrowserslistConfig, "packages/browserslist-config/"),
extend(packageEslintPlugin, "packages/eslint-plugin/"),
extend(packagePostcssConfigs, "packages/postcss-configs/"),
extend(packageStylelintConfigs, "packages/stylelint-configs/"),
extend(packageSwcConfigs, "packages/swc-configs/"),
extend(packageTsupConfigs, "packages/tsup-configs/"),
extend(packageWebpackConfigs, "packages/webpack-configs/"),
extend(sampleApp, "sample/app/"),
extend(sampleComponents, "sample/components/"),
extend(sampleUtils, "sample/utils/")
);

export default config;
5 changes: 5 additions & 0 deletions packages/browserslist-config/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
10 changes: 10 additions & 0 deletions packages/eslint-plugin/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Contributing

This entire repository uses this ESLint config to lint itself. It uses the live version in the `dist` directory, not the published version. You must build this package in order to lint the project.

## Inspecting configs

The easiest way to debug these configs is to use the config inspector provided by ESLint.

Run `pnpm dlx @eslint/config-inspector`. This will open the browser to a dashboard that will allow you to search by file or rule, and see exactly why a rule is applying to a specific file.

10 changes: 10 additions & 0 deletions packages/eslint-plugin/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = [
...workleapPlugin.configs.typescriptLibrary.map(conf => ({
...conf,
ignores: ["lib/plugins.d.ts"]
}))
];

export default config;
5 changes: 5 additions & 0 deletions packages/postcss-configs/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
5 changes: 5 additions & 0 deletions packages/stylelint-configs/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
5 changes: 5 additions & 0 deletions packages/swc-configs/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
5 changes: 5 additions & 0 deletions packages/tsup-configs/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
5 changes: 5 additions & 0 deletions packages/webpack-configs/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import workleapPlugin from "@workleap/eslint-plugin";

const config = workleapPlugin.configs.typescriptLibrary;

export default config;
Loading

0 comments on commit 9c5b87b

Please sign in to comment.