eslint-plugin-simple-import-sort

repository·main·Indexed 25 days ago

https://github.com/lydell/eslint-plugin-simple-import-sort

An ESLint plugin providing easy, autofixable import and export sorting. It supports TypeScript, Prettier, and dprint, focusing on a 'set and forget' experience. The plugin sorts based on the 'from' string to remain git diff friendly and allows custom grouping via regex-based configurations. It handles side-effect imports, Node.js builtins, packages, and relative imports while ensuring that associated comments move with the sorted items.

Tokens
5.9K
Snippets
13
Records
26
Agent score
69%

What's inside eslint-plugin-simple-import-sort

  1. Compare eslint-plugin-simple-import-sort with import/order

    main

    While eslint-plugin-import's import/order rule is widely used, eslint-plugin-simple-import-sort provides several specific advantages:

    • Comprehensive Sorting: Sorts imported/exported items, re-exports, type imports, and absolute imports.
    • Advanced Features: Supports comments, numerical sorting (e.g., ./img2.jpg before ./img10.jpg), and choosing where side-effect imports go.
    • Configuration: Uses a single, powerful option consisting of regexes rather than many individual options.
    • Error Reporting: Provides a single error per chunk of imports/exports, which is less 'noisy' in terms of total error count compared to import/order.
  2. Is sorting imports and exports safe?

    main

    Sorting is generally safe, but there are specific edge cases to consider:

    Side Effect Imports

    Imports that only run side effects (e.g., import "some-polyfill";) are not sorted; they stay in their original input order to prevent breaking code that relies on execution order.

    Re-exports and Name Collisions

    When re-exporting items (e.g., export * from "./one.js";), the plugin's sorting is safe in most environments (Node.js, Browsers, Webpack, Parcel, TypeScript) because they handle duplicate names via errors or by prioritizing the first declaration. However, Rollup may issue a warning and use the first declaration, which could theoretically be unsafe if you rely on a specific re-export order for name resolution.

    Best Practices

    • Avoid relying on side effects from re-exports.
    • If you have an import that both exports items and runs side effects, try to refactor it to separate those concerns.
  3. How exports are grouped and sorted

    main

    The plugin handles exports differently than imports:

    Grouping

    Unlike imports, there is no automatic grouping for exports. Grouping is performed manually using comments on their own line. A comment starts a new group, while comments on the same line as an export or within a block comment do not.

    Sorting

    • Re-exports: Sequences of re-exports (e.g., export * from "x") are sorted.
    • Other Exports: Other types of exports (e.g., export const x = 1) are not reordered relative to other export statements, but the items inside the braces are sorted.
    • Internal Item Sorting:
      • Imports: import { a as b } is sorted by the local name a (the "stable" name).
      • Exports: export { b as a } is sorted by the external name a (the interface name).
      • Types: import type and export type are sorted as if the type keyword were not there.

    Example of Manual Grouping

    export * from "x";
    export * from "y";
    
    // This comment starts a new group.
    export * from "a";
    
    /* This comment does not. */ export * from "b";
    
    /* But this does. */
    export * from "./";
    // This comment groups some more exports:
    export { e } from "../..";
    export { f } from "../Utils";
    export { g } from ".";
    export { h } from "./constants";
    export { i } from "./styles";
    
    // Other exports – the plugin does not touch these, other than sorting named
    // exports inside braces.
    export var one = 1;
    export let two = 2;
    export const three = 3;
    export function func() {}
    export class Class {}
    export type Type = string;
    export { named, other as renamed };
    export type { T, U as V };
    export default whatever;
  4. Limitations and non-configurable aspects of simple-import-sort

    main

    This plugin is designed to be minimal and simple. It does not provide extensive configuration options.

    What you cannot configure:

    • Sorting within groups: The internal sorting logic for each group is fixed.
    • Side effect imports: These always remain in their original order to ensure safety.

    If your project requires highly customized grouping or specific sorting logic within groups, consider using import/order from eslint-plugin-import instead.

  5. How imports are grouped and sorted

    main

    The plugin sorts imports by first identifying "chunks" (sequences of imports separated only by whitespace/comments) and then grouping them into sections separated by blank lines.

    Default Import Grouping Order

    1. Side effect imports: e.g., import "./setup" (not sorted internally).
    2. Node.js builtins: prefixed with node:, e.g., import * as fs from "node:fs".
    3. Packages: npm packages and Node.js builtins without node:, e.g., import react from "react".
    4. Absolute/Alias imports: e.g., import a from "/a" or import a from "@/foo".
    5. Relative imports: e.g., import a from "./a".

    Sorting Rules within Groups

    • Alphabetical: Sorted by the from string, case-insensitively, using Intl.Collator (numeric sorting enabled).
    • Directory Structure: For relative imports, higher-level directories come first: "../../utils" < "../utils" < ".".
    • Type Imports: If both import type and regular imports exist for the same source, import type comes first.
    • Import Styles: For the same source, the order is:
      1. Namespace imports (import * as X from "y")
      2. Default imports (import X from "y")
      3. Named imports (import { X } from "y")

    Note: Use eslint --fix or an ESLint editor extension to apply these changes automatically. Do not attempt to fix them manually.

  6. How the plugin handles Markdown files

    main

    The eslint-plugin-simple-import-sort plugin can sort imports within JavaScript code blocks embedded in Markdown files. It identifies code blocks marked with js or javascript and applies sorting logic to the imports found within those blocks, while ignoring the surrounding Markdown text and non-code elements like lists or plain text.

    import b1 from "b"
    import a1 from "a";

    Some text.

    code();
    
    import b2 from "b";
    import a2 from "a";
    
    code()
    
    import c2 from "c";
    
    import e2 from "e";
    import d2 from "d"
    
    ;[].forEach()
  7. Why the plugin sorts based on the 'from' string

    main

    Unlike some other rules that sort based on the first name after the import keyword, this plugin sorts based on the string following the from keyword.

    This approach is designed to be git diff friendly. When you add a new import to an existing module, the order of existing imports remains unchanged, preventing unnecessary line swaps and reducing merge conflicts.

  8. How comments and whitespace are handled during sorting

    main

    When sorting imports or exports, the plugin moves associated comments along with the items.

    Comment Rules

    • Comments placed above, at the start, or at the end of an import/export line move with that item.
    • Important: Comments located above the entire first import/export chunk or below the entire last chunk are never moved by the plugin. You must move these manually if they need to be repositioned.
    • Comments inside curly braces (e.g., import { /* comment */ a } from '...') are also moved with the items.

    Whitespace Rules

    • Blank Lines: The plugin removes all blank lines within a chunk of imports/exports, except for those inside /**/ comments and the blank lines it automatically adds between groups defined in your configuration.
    • One per line: The plugin enforces exactly one import or export per line.
    • Odd Spacing: Because the plugin re-uses existing whitespace to maintain compatibility with other ESLint rules, the autofix might occasionally produce slightly unusual spacing (e.g., missing spaces after commas). It is recommended to use Prettier or other ESLint whitespace rules to clean this up.
  9. How to use this plugin with dprint

    main

    If you use dprint for formatting, note that dprint sorts imports but does not enforce grouping. To prevent conflicts between the two tools, you should disable dprint's import sorting in your configuration file.

    {
      "typescript": {
        "module.sortImportDeclarations": "maintain"
      }
    }
  10. Configure eslint-plugin-simple-import-sort in .eslintrc.*

    main

    To use the plugin with traditional ESLint configuration files, add "simple-import-sort" to the plugins array and enable the simple-import-sort/imports and simple-import-sort/exports rules.

    Note: You must ensure parserOptions are configured (e.g., sourceType: "module") so ESLint can parse import and export syntax.

    Important: Do not use this plugin simultaneously with sort-imports or import/order rules to avoid conflicts.

    {
      "plugins": ["simple-import-sort"],
      "rules": {
        "simple-import-sort/imports": "error",
        "simple-import-sort/exports": "error"
      },
      "parserOptions": {
        "sourceType": "module",
        "ecmaVersion": "latest"
      }
    }
  11. Explore configuration examples

    main

    To understand how to configure eslint-plugin-simple-import-sort for different sorting outcomes, the primary resource is the .eslintrc.js file in the root of the repository. This file contains various configuration patterns accompanied by comments explaining their effects.

    If you want to see the final result of applying these configurations, you can inspect the snapshots in test/__snapshots__/examples.test.js.snap, which show the code state after running eslint --fix.

  12. How to remove all blank lines between imports

    main

    By default, the plugin adds a blank line between each group defined in your configuration. To remove all blank lines between imports, configure the groups option to contain only a single inner array.

    Instead of the default (which uses multiple inner arrays), use a single array containing all your regex patterns.