Skip to content

Commit

Permalink
📝 Finish documentation/README
Browse files Browse the repository at this point in the history
  • Loading branch information
sergei-maertens committed Jan 6, 2025
1 parent e796fc5 commit 9bd9f0b
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 43 deletions.
187 changes: 149 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,29 @@
Shared configuration for [ESLint](https://eslint.org/) for consistent rules across
Maykin projects.

[![NPM Version](https://img.shields.io/npm/v/%40maykinmedia%2Feslint-config)](https://www.npmjs.com/package/@maykinmedia/eslint-config)

This package exposes a set of standard/recommended rules for ESLint code checks. You can
still decide to override certain rules/configurations on a per-project basis - a nice
feature of ESLint's flat config format. See below for example configurations.

## Installation

**Requirements**

* ESLint v8+, v9 recommended as it defaults to flat config.

**Install from npm**
The recommended installation includes all optional plugins. These should not get in the
way if you're not using all features (e.g. a project without React or Typescript).

```bash
npm install \
--save-dev \
eslint \
@maykinmedia/eslint-config \
eslint-plugin-import \
eslint-plugin-jsx-a11y \
eslint-plugin-prettier \
eslint-plugin-react \
eslint-plugin-react-hooks \
eslint-plugin-storybook \
typescript-eslint \
eslint-import-resolver-typescript \
@maykinmedia/eslint-config
eslint-import-resolver-typescript
```

Optional plugins are specified as peer dependencies, required plugins will be pulled in
Expand All @@ -38,53 +36,94 @@ automatically.
Create a file `eslint.config.js` and compose the configuration:

```js
// eslint.config.mjs
import {ignoreBuildArtifacts} from '@maykinmedia/eslint-config';
import recommended from '@maykinmedia/eslint-config/recommended';

export default [
ignoreBuildArtifacts(['dist', 'build']), // dist and build are the defaults
// dist, build and storybook-static are the defaults
ignoreBuildArtifacts(['dist', 'build', 'storybook-static']),
...recommended,
// Project-specific overrides...
// {
// 'name': 'project:overrides',
// 'rules': {
// 'some-rule': 'off',
// },
// },
];
```

When there are conflicts between rules, the last one wins.
See [Overrides](#overrides) for how to add overrides.

You can use the [config-inspector](https://github.com/eslint/config-inspector) to
inspect what the final composed config is for your project.

### Recommended

Required plugins:
The recommended configuration assumes modern setups with Typescript, React and Storybook.
Even if you don't use all of these components of the stack, you can still use the
recommended configuration.

For company-wide consistency, we really encourage you to use the recommended config.

**Required plugins**

* [React](#react) plugins
* [Typescript](#typescript) plugins
* `eslint-plugin-import`
* `eslint-plugin-prettier`
* `eslint-plugin-storybook`

...
**Usage**

### Basic
See [Usage](#usage) above.

...
## Configuration parts

### React
The (recommended) and available configuration is broken up around various (optional)
plugins. The recommended config is composed from these parts. Each part is documented
below.

### Base

> [!TIP]
> Included in the recommended config.
Required plugins:
The base configuration is the absolute minimum. It sets up the environment and enables
the recommended rules from ESLint itself. Additionally, it provides a helper to prevent
linting build artifacts, as that hurts performance.

* `eslint-plugin-jsx-a11y`
* `eslint-plugin-react`
* `eslint-plugin-react-hooks`
```js
import {base, ignoreBuildArtifacts} from '@maykinmedia/eslint-config/base';

export default [
ignoreBuildArtifacts(['dist']),
...base,
]
````

### Typescript

> [!TIP]
> Included in the recommended config.

The typescript configuration enables parsing of TS source code with type annotations.

We essentially re-export the `typescript-eslint` recommended configuration without
additional tweaks.

**Required plugins**

* `typescript-eslint`

```js
import typescript from '@maykinmedia/eslint-config/typescript';
export default [
...,
...typescript,
...,
]
```

### React

> [!TIP]
> Included in the recommended config.

The React config enables:

Expand All @@ -93,17 +132,23 @@ The React config enables:
* the JSX automatic runtime
* react hooks checking

**Required plugins**

* `eslint-plugin-jsx-a11y`
* `eslint-plugin-react`
* `eslint-plugin-react-hooks`

**react-intl support**

If you use react-intl for internationalization, you'll want to use the relevant
override if you're not using the recommended config.

```js
// eslint.config.mjs
import {reactIntl} from '@maykinmedia/eslint-config/react';
import {react, reactIntl} from '@maykinmedia/eslint-config/react';
export default [
...,
...react,
reactIntl,
...,
]
Expand All @@ -124,35 +169,101 @@ relevant rule in your [Project specific overrides](#project-specific-overrides):
}
```


### Typescript
### Storybook

> [!TIP]
> Included in the recommended config.

Required plugins:
Storybook itself provides a plugin to lint your story files. Additionally, we enable
checking of the `.storybook` configuration folder.

* `typescript-eslint`
**Required plugins**

...
* `eslint-plugin-storybook`

### Storybook
```js
import storybookConfig from '@maykinmedia/eslint-config/storybook';
export default [
...,
...storybookConfig,
...,
]
```

### Import/export

> [!TIP]
> Included in the recommended config.

Required plugins:
Import/export linting protects against broken imports and can help enforce consistent
import/export styles. Additionally, our rules block using "legacy" `require` and `define`
import systems in favour of the `import`/`export` module system. We also prevent
bundler-specific import syntax (e.g. webpack-specific import directives) to avoid tight
coupling with a particular bundler.

* `eslint-plugin-storybook`
The recommended configuration assumes you're either using Typescript, or `jsconfig.json`
with base URLs/path aliases and for that reason, the `src` directory is automatically
added to the module resolution.
**Required plugins**
* `eslint-plugin-import`
* `eslint-import-resolver-typescript` when integrating with Typescript
```js
import importConfig from "@maykinmedia/eslint-config/imports";
import typescriptImports from "@maykinmedia/eslint-config/import-with-typescript";
...
export default [
importConfig,
...typescriptImports,
]
```
### Project specific overrides
...
Finally, and especially when adapting existing projects, you may want to apply certain
project-specific overrides. This can be because you're using something else, or there are
known linting violations that are just too much work to address right now.

You can easily apply overrides on top of the recommend config by including your own
configuration objects - ESLint applies them all and on conflict, the last one wins.

For example, a recommend config with project specific overrides:

```js
import {ignoreBuildArtifacts} from '@maykinmedia/eslint-config';
import recommended from '@maykinmedia/eslint-config/recommended';
export default [
// dist, build and storybook-static are the defaults
ignoreBuildArtifacts(['dist', 'build', 'storybook-static']),
...recommended,
// Project-specific overrides.
{
name: 'project/ignore-tests',
ignores: ['**/*.{spec,test}.{js,jsx,ts,tsx}'],
},
{
name: 'project/allow-webpack-imports',
rules: {
'import/no-webpack-loader-syntax': 'off',
},
}
];
```

We recommend always providing a `name` for a rule as that makes it easier to identify
when using the config inspector.

## Contributing

> [!NOTE]
> It's likely that only contributions from Maykin employees will be accepted, as this
> package is aimed at Maykin projects. However, we won't stop you from making bugfixes and
> suggestions, we just can't promise that we'll agree with them.

The various configuration snippets are in the `src/` folder. They are organized based on
the optional dependencies, i.e. you should be able to use the base config without having
`eslint-plugin-react` installed, or `typescript` support should be available without the
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
},
"homepage": "https://github.com/maykinmedia/eslint-config#readme",
"dependencies": {
"eslint": ">=8.57.1",
"@eslint/js": ">=8.57.1",
"globals": ">=15.14.0"
},
"peerDependencies": {
"eslint": "^8.57.1 || ^9.x",
"eslint-import-resolver-typescript": ">=3.7.0",
"eslint-plugin-import": ">=2.31.0",
"eslint-plugin-jsx-a11y": ">=6.10.2",
Expand All @@ -47,8 +47,6 @@
"typescript-eslint": ">=8.19.0"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
"eslint": "^9.17.0",
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
Expand Down
4 changes: 2 additions & 2 deletions src/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ const base = [
* directories listed.
*
* @param {String[]} dirNames Pass in an array of (relative) directory names, without slashes.
* By default, `dist` and `build` are ignored.`
* By default, `dist`, `build` and `storybook-static` are ignored.
* @return {{name: string, ignores: string[]}} A config entry with glob patterns to ignore the specified dirs.
*/
const ignoreBuildArtifacts = (dirNames = ["dist", "build"]) => ({
const ignoreBuildArtifacts = (dirNames = ["dist", "build", "storybook-static"]) => ({
name: "project/ignore build artifacts",
ignores: dirNames.map(name => `${name}/**/*`),
});
Expand Down

0 comments on commit 9bd9f0b

Please sign in to comment.