Easy autofixable import sorting.
Easy autofixable import sorting.
Easy autofixable import sorting.
eslint --fix – no new toolinggit diff friendlyrequireThis is for those who use eslint --fix (autofix) a lot and want to completely forget about sorting imports!
import React from "react";
import Button from "../Button";
import styles from "./styles.css";
import type { User } from "../../types";
import { getUser } from "../../api";
import PropTypes from "prop-types";
import classnames from "classnames";
import { truncate, formatNumber } from "../../utils";⬇️
import classnames from "classnames";
import PropTypes from "prop-types";
import React from "react";
import { getUser } from "../../api";
import type { User } from "../../types";
import { formatNumber, truncate } from "../../utils";
import Button from "../Button";
import styles from "./styles.css";[More examples][examples]
npm install --save-dev eslint-plugin-simple-import-sortℹ️ This is an [ESLint] plugin. [Getting Started with ESLint][eslint-getting-started]
[eslintrc]: Add "simple-import-sort" to the "plugins" array in your .eslintrc.* file, and add the rules for sorting imports and exports. By default ESLint doesn’t parse import syntax – the "parserOptions" is an example of how to enable that.
{
"plugins": ["simple-import-sort"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest"
}
}[eslint.config.js (flat config)]: Import eslint-plugin-simple-import-sort, put it in the plugins object, and add the rules for sorting imports and exports. With flat config, import syntax is enabled by default.
import simpleImportSort from "eslint-plugin-simple-import-sort";
export default [
{
plugins: {
"simple-import-sort": simpleImportSort,
},
rules: {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
},
},
];Make sure not to use other sorting rules at the same time:
ℹ️ Note: There used to be a rule called
"simple-import-sort/sort". Since version 6.0.0 it’s called"simple-import-sort/imports".
This example uses eslint-plugin-import, which is optional.
It is recommended to also set up Prettier, to help formatting your imports (and all other code) nicely.
{
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest"
},
"plugins": ["simple-import-sort", "import"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error"
}
}"sourceType": "module" and "ecmaVersion": "latest" are needed so ESLint doesn’t report import and export as syntax errors.simple-import-sort/imports and simple-import-sort/exports are turned on for all files.This plugin is not for everyone. Let me explain.
For a long time, this plugin used to have no options, which helped keeping it simple.
While the human alphabetical sorting and comment handling seems to work for a lot of people, grouping of imports is more difficult. Projects differ too much to have a one-size-fits-all grouping.
I’ve decided to have this single option but nothing more. Here are some things you can’t configure:
If you want more options, I recommend using the [import/order] rule (from eslint-plugin-import) instead. It has plenty of options, and the maintainers seem interested in expanding the feature where it makes sense.
Then why does this plugin exist? See [How is this rule different from import/order?][import/order-comparison].
If we start adding more options to this plugin, it won’t be eslint-plugin-simple-import-sort anymore. Eventually it would have no reason to exist – effort would be better spent contributing to [import/order].
I made this plugin for myself. I use it in many little projects and I like it. If you like it too – I’m very glad to hear! But everyone won’t like it. And that’s ok.
This plugin is supposed to be used with autofix, ideally directly in your editor via an ESLint extension, or with eslint --fix otherwise.
This section is for learning how the sorting works, not for how to manually fix errors. Use autofix!
TL;DR: First group, then sort alphabetically.
First, the plugin finds all chunks of imports. A “chunk” is a sequence of import statements with only comments and whitespace between. Each chunk is sorted separately. Use [import/first] if you want to make sure that all imports end up in the same chunk.
Then, each chunk is grouped into sections with a blank line between each.
import "./setup": Side effect imports. (These are not sorted internally.)import * as fs from "node:fs": Node.js builtin modules prefixed with node:.import react from "react": Packages (npm packages and Node.js builtins without node:).import a from "/a": Absolute imports and other imports such as Vue-style @/foo.import a from "./a": Relative imports.Note: The above groups are very loosely defined. See [Custom grouping] for more information.
Sequences of re-exports (exports with from) are sorted. Other types of exports are not reordered.
Unlike imports, there’s no automatic grouping of exports. Instead a comment on its own line starts a group. This leaves the grouping up to you to do manually.
The following example has 3 groups (one with “x” and “y”, one with “a” and “b” and one with “./”):
export * from "x";
export * from "y";
// This comment starts a new group.
/* This one does not. */ export * from "a"; // Neither does this one.
/* Nor this
one */ export * from "b";
/* But this one does. */
export * from "./";Each group is sorted separately, and the groups themselves aren’t sorted – they stay where you wrote them.
Without the grouping comments the above example would end up like this:
export * from "./";
/* This one does not. */ export * from "a"; // Neither does this one.
/* Nor this
one */ export * from "b";
export * from "x";
export * from "y";Within each section, the imports/exports are sorted alphabetically on the from string (see also [“Why sort on from?”][sort-from]). Keep it simple! It helps looking at the code here:
const collator = new Intl.Collator("en", {
sensitivity: "base",
numeric: true,
});
function compare(a, b) {
return collator.compare(a, b) || (a < b ? -1 : a > b ? 1 : 0);
}In other words, the imports/exports within groups are sorted alphabetically, case-insensitively and treating numbers like a human would, falling back to good old character code sorting in case of ties. See [Intl.Collator] for more information. Note: Intl.Collator sorts punctuation in some defined order. I have no idea what order punctuation sorts in, and I don’t care. There’s no ordered “alphabet” for punctuation that I know of.
There’s one addition to the alphabetical rule: Directory structure. Relative imports/exports of files higher up in the directory structure come before closer ones – "../../utils" comes before "../utils", which comes before ".". (In short, . and / sort before any other (non-whitespace, non-control) character. ".." and similar sort like "../," (to avoid the “shorter prefix comes first” sorting concept).)
If both import type and regular imports are used for the same source, the type imports come first. Same thing for export type. (You can move type imports to their own group, as mentioned in [custom grouping].)
If multiple import styles are used for the same source, there is a defined order:
// First namespace imports:
import * as Circle from "circle;
// Then default imports:
import createCircle from "circle";
// Then named imports:
import { radius } from "circle";That is especially useful if you need to have both a namespace import and want to import a few things separately (since that cannot be combined into a single import statement). With the above rule, the imports end up in a deterministic order.
Finally, if there are multiple imports for the same source with the same style, it’s recommended to use [import/no-duplicates] to join them into one import.
…Regardless of group, imported items are sorted like this:
import {
// Numbers are sorted by their numeric value:
img1,
img2,
img10,
// Then everything else, alphabetically:
k,
L, // Case insensitive.
m as anotherName, // Sorted by the “external interface” name “m”, not “anotherName”.
m as tie, // But do use the file-local name in case of a tie.
// Types are sorted as if the `type` keyword wasn’t there.
type x,
y,
} from "./x";Exported items are sorted even for exports without from (even though the whole export statement itself isn’t sorted in relation to other exports):
export {
k,
L, // Case insensitive.
anotherName as m, // Sorted by the “external interface” name “m”, not “anotherName”.
// tie as m, // For exports there can’t be ties – all exports must be unique.
// Types are sorted as if the `type` keyword wasn’t there.
type x,
y,
};
export type { A, B, A as C };At first it might sound counter-intuitive that a as b is sorted by a for imports, but by b for exports. The reason for doing it this way is to pick the most “stable” name. In import { a as b } from "./some-file.js", the as b part is there to avoid a name collision in the file without having to change some-file.js. In export { b as a }, the b as part is there to avoid a name collision in the file without having to change the exported interface of the file.
There is one option (see [Not for everyone]) called groups that is useful for a bunch of different use cases.
groups is an array of arrays of strings:
type Options = {
groups: Array<Array<string>>;
};Each string is a regex (with the [u flag]). The regexes decide which imports go where. (Remember to escape backslashes – it’s "\\w", not "\w", for example.)
The inner arrays are joined with one newline; the outer arrays are joined with two – creating a blank line. Tha
No open issues yet, or sync has not completed.