Skip to content

connorjs/eslint-config-connorjs

Repository files navigation

eslint-config-connorjs

My (@connorjs) preferred ESLint configuration. With ESLint flat config.

Use it directly (§ Install) or take inspiration from it (§ Rules and reasoning).

🛑 IMPORTANT

eslint-comments/require-description is the single most important rule to configure! Please use it.

🟢 Tip: I highly recommend eslint-plugin-unicorn, which my config uses.

Table of contents

Install

  1. Add the dependency

    npm i -D eslint-config-connorjs
  2. Include the config in your ESLint flat config.

    import connorjsConfig from "eslint-config-connorjs";
    
    export default [
    	// earlier configuration
    	...connorjsConfig,
    	// later
    ];

To learn more about ESLint flat config, check out the blog posts or the documentation.

Project structure

The lib directory contains the ESLint configuration files. It groups them by “use case.” A use case could represent an entire language (html or json for example) or a tool (react or vitest).

Splitting by use case helps to copy desired configuration or building a functional form of the ESLint config. (See Sheriff for an example of the functional form.)

Rules and reasoning

The remainder of the README discusses the rules, configurations, and plugins used and why I used them.

The 🔧 emoji indicates that configured rules are automatically fixable with --fix.

🟢 Tip: The source code has inline comments that may provide more detail.

Base rules

The base rules config apply to all file types.

JSON

The JSON config applies to all JSON files. It handles JSONC (JSON with comments) and JSONC-like files.

  • Configures jsonc-eslint-parser as the parser for the .json and .jsonc files.

    It does not lint package-lock.json.

  • Includes eslint-plugin-jsonc and registers its recommended-with-json and prettier rule sets.

  • 🔧 Configures sorting rules to standardize the order (no need to think or worry about the “best” order) and reduces merge conflicts. Feel free to eslint-disable at call sites.

  • Allows comments in JSONC and JSONC-like files (for example, tsconfig.json).

  • 🔧 Configures an explicit sort order for package.json keys. See the code for details.

    🔷 Note: This overrides the previous jsonc/sort-keys configuration. You can configure specific sort orders for other files using similar logic.

JavaScript and TypeScript

The JS and TS config applies to all JS and TS files: cjs,js,ts,tsx. The largest configuration set!

  • Configures language options.

    • ecmaVersion: latest because projects use bundlers or other build tools to transpile to target versions.

    • Includes isomorphic globals (shared by node and the browser) via globals

    • Also see the @typescript-eslint/parser documentation

  • 🔧 Configures sorting rules to standardize the order (no need to think or worry about the “best” order) and reduces merge conflicts. Feel free to eslint-disable at call sites. They are case-insensitive.

  • Includes @eslint/js recommended rule set.

  • Includes eslint-plugin-sonarjs recommended rule set.

  • Includes eslint-plugin-unicorn recommended rule set and configures additional rules from unicorn. Some specific call-outs follow.

    • 🔧 Configures an allow list for unicorn/prevent-abbreviations to allow some abbreviations. Example: Allow props, which React commonly uses.

    • 🔧 Configures patterns for unicorn/string-content to enforce better string content. Example: Use unicode arrow instead of hyphen and greater than (->).

      The auto-fix feature makes this rule very useful. See the source code for a “smart quotes” pattern.

  • Uses typescript-eslint and includes its recommended-type-checked and stylistic-type-checked rule sets.

  • Uses eslint-plugin-simple-import-sort and eslint-plugin-import to configure import rules. Some specific call-outs follow.

    • 🔧 Includes simple-import-sort/imports and simple-import-sort/exports to sort the imports and re-exports. See the Sort order docs.

      I recommend the default configuration instead of creating your own order.

    • Includes eslint-plugin-import recommended rule set.

    • Configures import/no-default-export to disallow default exports.

      I have experienced various issues resulting from default exports over the years, so I strongly recommend configuring this rule. You can always eslint-disable at the call site when you need it and explain why (example: dynamic imports for React code-splitting point).

      1. Naming exports leads to a stronger contract and can help refactoring.
      2. You can use as syntax to rename named exports very easily, so the supposed benefit of “name default exports whatever you want” has little benefit in practice.
      3. I want to add more of my reasons, so TODO!

      The ESLint configuration opts-out known configuration files that require default exports (example: storybook files).

    • Configures import/no-anonymous-default-export to disallow anonymous default exports in the case that you eslint-disable the import/no-default-export rule.

    • 🔧 Uses @typescript-eslint/consistent-type-imports and import/consistent-type-specifier-style to enforce consistent usage of type imports.

      We need both rules for best fix-it developer experience: one to add type and the other to fix the placement.

React

The react config applies to all typescript files (ts and tsx) and only makes sense to use in a React project.

  • Uses eslint-plugin-jsx-a11y and its recommended rule set.

  • Uses eslint-plugin-react and its recommended and jsx-runtime rule sets.

  • Uses eslint-plugin-react-hooks and its recommended rule set.

  • Configures react/destructuring-assignment to disallow destructuring props. (Controversial, I know.)

    I find it harder to update components that use destructuring. Plus I think it looks bad with inline types given TypeScript usage.

  • Configures react/forbid-component-props to disallow props. (Example: style to disallow inline styles.)

  • 🔧 Configures [react/function-component-definition] to enforce component definition consistency.

    Uses “function declarations” for named components because they are the only way to support generics in TSX, so using it for consistency. Remember: This will auto-fix.

    Uses “arrow functions” for unnamed components to emphasize unnamed and for nice lambda readability (example: pass to map).

  • 🔧 Enables react/hook-use-state to enforce symmetric naming of the useState hook value and setter variables.

  • 🔧 Configures react/jsx-boolean-value and react/jsx-curly-brace-presence to enforce consistent JSX styles. See the code for details.

  • Configures the following rules to force a comment explaining the use case. While this may seem like extra work, it helps catch improper usage.

    • react/jsx-no-leaked-render
    • react/jsx-props-no-spreading
    • react/no-array-index-key
    • react/no-danger

HTML

The HTML config applies to all HTML files.