1.0.0 • Published 8 months ago

@krakentech/eslint-config v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
8 months ago

This package provides a wide range of "recommended" ESLint configs with the goal of minimising end-user configuration and increasing consistency across projects. It is designed around ESLint v9 to allow for easily shareable, modular and extensible configurations by leveraging the new "Flat" config files.

Installation

We publish our ESLint config publicy on npm. No registry token or authentication is required to install the config. Install it alongside the latest eslint version using your preferred package manager:

pnpm add -D @krakentech/eslint-config eslint
yarn add -D @krakentech/eslint-config eslint
npm install --save-dev @krakentech/eslint-config eslint

!NOTE If you are using a monorepo it's still recommended to install the package at the root of the project. ESlint v9 is now able to apply rules top down, making it trivial to limit specific rule-sets to the right files. For example, the recommended NextJS package can easily be restricted to apps/web if that is the only NextJS application in the monorepo.

Configuration

ESLint v9 now enforces the use of a file named eslint.config.js. This should be placed at the root of your project. Configuration of the whole repository can be done from this single file. Simply load the package and export linters.load(FlatConfig, ...).

Each FlatConfig only requires the user to define which files should have which plugins applied to them (or ignores) and which plugins the config extends from. You can pass as many configs as you like.

!IMPORTANT If you don't define any files for a config, the default behaviour it to lint all project files! This may affect performance.

// eslint.config.js

const linters = require("@krakentech/eslint-config");

module.exports = linters.load(
  // Ignore all node_modules and dist folders
  {
    ignores: ["**/node_modules/**", "**/dist/**"],
  },
  // Apply recommended typescript rules to all
  // Typescript files in the repo
  {
    files: ["**/*.{ts,tsx,mts,cts}"],
    extends: linters.configs.typescript.recommended,
  },
);
// eslint.config.js

const linters = require("@krakentech/eslint-config");

module.exports = linters.load(
  // Also ignore next build folder
  {
    ignores: [
      "**/node_modules/**",
      "**/dist/**",
      "**/.next/**"
    ],
  },
  // Apply recommended next rules to all apps
  {
    files: ["apps/**/*.{ts,tsx}"],
    extends: linters.configs.next.recommended,
  },
  // Only apply typescript rules to packages
  {
    files: ["packages/**/*.{ts,mts,cts}"],
    extends: linters.configs.typescript.recommended,
  },
);

!TIP We support both CJS and ESM config files! You can use import and export default if your package package type is set to module.

Fine tuning configurations

Whilst we suggest that you try to use the recommended configurations where possible to maintain consistency across projects, it is still simple to "extend" our recommended configs and "override" specific rules.

Simple Typescript Package

For example, lets say we want to create a ReactJS project that uses Typescript and disables the @typescript-eslint/no-explicit-any rule:

// eslint.config.js

const linters = require("@krakentech/eslint-config");

module.exports = linters.load(
  // ... other configs
  {
    files: ["**/*.{ts,tsx}"],
    extends: [
      // Load recommended Javascript rules
      ...linters.configs.javascript.recommended,
      // Load the recommended typescript configs
      ...linters.configs.typescript.recommended,
      // Then extend it with the React config
      ...linters.configs.react.recommended,
    ],
    // Override a specific rule
    rules: {
      "@typescript-eslint/no-explicit-any": "off",
    },
  },
);

Monorepo with multiple apps, packages and tests

// eslint.config.js

const linters = require("@krakentech/eslint-config");

module.exports = linters.load(
  // Global ignores across the whole repo
  {
    ignores: ["**/node_modules/**", "**/build/**", "**/*.typegen.*/**"],
  },
  // Apply Javascript recommended rules to all js(x) and ts(x) files
  {
    files: ["**/*.{js,jsx,ts,tsx}"],
    extends: linters.configs.javascript.recommended,
  },
  // Apply next recommended rules to all apps
  {
    files: ["apps/**/*.{ts,tsx}"],
    extends: linters.configs.next.recommended,
  },
  // Only apply typescript rules to packages
  {
    files: ["packages/**/*.{ts,mts,cts}"],
    extends: linters.configs.typescript.recommended,
  },
  // Applies react rules to all react files. This should also catch most test
  // files too.
  {
    files: ["**/*.{jsx,tsx}"],
    extends: [
      ...linters.configs.react.recommended, // Includes jsxa11y
    ],
  },
  // Applies jest rules to test files
  {
    files: ["**/*.spec.{js,jsx,ts,tsx}"],
    extends: linters.configs.jest.recommended,
  },
);

!TIP Some plugins have "utility" configs that do something specific to that plugin (usually to disable rules). Use these the same way you would use the base configs.

export type LinterConfig = {
  base: FlatConfig;
  recommended: ConfigArray;
  utils?: Record<string, FlatConfig>;
};

export type PackageConfig = {
  load: (...configs: InfiniteDepthConfigWithExtends[]) => ConfigArray;
  configs: Record<string, LinterConfig>;
};

Plugins

The following plugins are supported by this package. Many of the recommended ConfigArray's only contain the base plugin, however, the recommended Typescript, React and NextJS configs contain multiple plugins, for which the table below also indicates the other plugins that are loaded.

PluginTypescriptReactNextJS
@eslint/js
typescript-eslint
eslint-plugin-import
eslint-plugin-simple-import-sort
eslint-plugin-react
eslint-plugin-react-hooks
eslint-plugin-jsx-a11y
@next/eslint-plugin-next
eslint-plugin-turbo
@vitest/eslint-plugin
eslint-plugin-jest
eslint-plugin-prettier

!IMPORTANT The recommended configs are configurations we think you should use in your projects, not that they necessarily use the recommended rules sets. Whilst most do use the recommended rule sets, it's good to check which rules sets using the JSDoc strings on each export or the plugin details below.

Examples

Base Configs

@eslint/js

Overrides

  • no-console - ["error", { allow: ["warn"] }]

typescript-eslint

We use the "Strict TypeChecked" rules (which automatically brings in the "Recommended" rules) to provide the most accurate type checking.

Overrides

  • @typescript-eslint/no-unused-vars
    • Allows the use of the _ prefix for unused variables
    • Will ignore unused destructured rest siblings: { ignoreMe, ...butNotMe } = someObject
  • @typescript-eslint/consistent-type-imports
  • Prefers types are always imported using the type keyword
  • e.g. import { type Foo } over import { Foo }
  • This works well the fixable rule import/consistent-type-specifier-style to ensure import consistency.

The following have been disabled:

  • @typescript-eslint/no-confusing-void-expression - Off
  • @typescript-eslint/restrict-template-expressions - Off
  • @typescript-eslint/no-unsafe-enum-comparison - Off
  • @typescript-eslint/unbound-method - Off
  • @typescript-eslint/no-floating-promises - Off

!TIP We provide the configs.typescript.utils.disableTypeChecking utility to disable the type checking rules if you need to disable type checking for whatever reason (e.g. old JSX only components).


eslint-plugin-import and eslint-plugin-simple-import-sort

We use both packages in configs.imports.recommended. We prefer eslint-plugin-simple-import-sort for import sorting because it requires less configuration to apply sensible sorting, is easier to configure and only creates an single issue if there's an error in the sorting. We also include eslint-plugin-import for a few rules that the former does not handle:

  • import/first - Ensure all imports appear before other statements.
  • import/newline-after-import - Enforce a newline after import statements.
  • import/no-duplicates - Forbid repeated import of the same module in multiple places.
  • import/consistent-type-specifier-style - Ensure that we consistently use import { type Foo }.

We provide the ability to disable the simple-import-sort plugin if it does not fit well with your project. Simply extend your config with this utility like so:

// eslint.config.js

import linters from "@krakentech/eslint-config";

export default linters.load({
  files: ["**/*.{ts,tsx}"],
  extends: [
    ...linters.configs.typescript.recommended,
    linters.configs.imports.utils.disableSimpleImportSort,
  ],
});

eslint-plugin-react, eslint-plugin-react-hooks and eslint-plugin-jsx-a11y

Overrides

  • react/prop-types - Off.
  • react/react-in-jsx-scope - Off.

@next/eslint-plugin-next


eslint-plugin-turbo


@vitest/eslint-plugin


eslint-plugin-jest


eslint-plugin-prettier

!IMPORTANT Prettier is not enabled by default in our recommended configs. The official advice by both the Prettier team and the ESLint team is to not integrate Prettier rules into your ESLint config. Formatters should be something you forget about; lots of red squiggly lines in your editor can be distracting as well as less performant.

However, it is expected that users implement Prettier into their workflow at some point. Ideally users integrate Prettier into their editors, or you run Prettier as a file watcher.

Alternatively (or in addition to), you can conditionally enable Prettier during CI to ensure committed code is formatted correctly:

// eslint.config.js

// This is the common CI ennvar, however, adjust to your system
const isCI = process.env.CI;

export default linters.load(
  ...
  // Enable Prettier in CI only
  isCI && {
    // No files array will lint all files
    extends: linters.configs.recommended.prettier,
  },
  ...
};

!NOTE Prettier should be enabled as your last config so that it can override any rules it might conflict with.

Rule Comparison

This table details which rules have been added or removed from the last major release (also compatibility with Biome given it looks like a promising upgrade from ESLint).