深入解析 ESLint sort-imports 规则:import 声明排序的完整实战指南
深入解析 ESLint sort-imports 规则import 声明排序的完整实战指南【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本篇技术指南以 ESLint 内置规则sort-imports为主题完整讲解该规则如何对模块中的import声明进行先按语法形态分组、再按字母序排列的双重排序校验覆盖全部五个配置选项ignoreCase、ignoreDeclarationSort、ignoreMemberSort、memberSyntaxSortOrder、allowSeparatedGroups的默认值与自定义用法。读完本文你将能够在项目配置中精准启用并调优该规则理解--fix自动修复的边界并结合 lib/rules/sort-imports.js 源码掌握其底层排序原理。为什么需要为 import 排序import语句用于从外部模块引入已导出的成员函数、对象或原始值。ES Module 的导入语法形态多样可以按需引入单个成员、多个成员或整体引入整个模块// single - 导入单个成员 import myMember from my-module.js; import {myOtherMember} from my-other-module.js; // multiple - 导入多个成员 import {foo, bar} from my-module.js; // all - 导入全部成员myModule 包含该模块导出的所有绑定 import * as myModule from my-module.js;此外还有一种特殊情况import语句可以只导入模块而不引入任何导出绑定用于那些不导出内容、但会在执行时运行自身代码或修改全局上下文对象的模块// none - 导入模块但不引入任何导出绑定 import my-module.js当模块中存在大量 import 声明时一份有序排列的 import 清单能让开发者更容易阅读代码、更快找到需要的导入项。sort-imports规则正是为这一目的而生它纯粹是一个代码风格style层面的规则——排序与否不会影响代码的运行行为只影响可读性与维护体验。在规则元数据中它的type被标记为suggestion且recommended: false即默认不纳入eslint:recommended推荐集见 docs/src/_data/rules.json 中 sort-imports 条目从 docs/src/_data/rule_versions.json 可确认该规则自 ESLint 2.0.0-beta.1 起便已存在。Rule Details双重排序逻辑该规则检查文件中所有import声明并验证两件事先按所用的成员语法形态排序语法分组顺序由memberSyntaxSortOrder决定默认为none→all→multiple→single再按第一个成员或别名的名称进行字母序排序。也就是说排序键是两个维度的组合语法形态的优先级永远高于名称的字母序。默认情况下import xxxnone必须排在最前import * as xxxall次之import {a, b}multiple再次import a from ...single排在最后同一种语法形态内部再按首个本地成员名/别名逐字符比较。从 lib/rules/sort-imports.js 的源码可以看到语法形态的判定函数usedMemberSyntax其判定规则完全基于 AST 节点ImportDeclaration的specifiers数组specifiers.length 0→ 返回none第一个 specifier 类型为ImportNamespaceSpecifier→ 返回allspecifiers.length 1→ 返回single其余情况多个成员→ 返回multiple。排序时规则通过getMemberParameterGroupIndexlib/rules/sort-imports.js取当前与上一条声明在memberSyntaxSortOrder数组中的索引进行比较索引不同则校验语法顺序产生unexpectedSyntaxOrder消息索引相同则比较getFirstLocalMemberNamelib/rules/sort-imports.js取到的首个本地成员名若当前名小于上一条名字符串默认比较与sort-vars保持一致则报告sortImportsAlphabetically消息。--fix 自动修复能力与边界该规则在命令行使用--fix选项时可以自动修复部分问题单行内的多个成员会被自动排序例如import { b, a } from foo.js会被修正为import { a, b } from foo.js但是多行 import 声明之间的顺序不会被重排需要开发者手动调整。在 tests/lib/rules/sort-imports.js 中可以看到单行成员排序的测试证据import {b, a, d, c} from foo.js;经自动修复后输出为import {a, b, c, d} from foo.js;。自动修复还有一条重要的安全边界——含注释的成员列表不修复。源码中的fix函数lib/rules/sort-imports.js在重排前会检查每个ImportSpecifier前后是否有关联注释只要存在注释就返回null放弃修复仅保留报告不执行修改。这是因为重排会打乱注释与成员的对应关系可能造成语义误解。测试用例也验证了这一点tests/lib/rules/sort-imports.js例如import {zzzzz, /* comment */ aaaaa} from foo.js;会报告错误但output为null不修复。值得一提的是修复函数还会保留成员之间的原始间隔文本逗号、换行、缩进等通过fixer.replaceTextRange在排序后拼接回原样因此跨多行的成员列表也能被安全地重排测试中baz as qux这样的别名按本地名qux参与排序见 tests/lib/rules/sort-imports.js。Options五个配置项总览规则接受一个对象作为配置包含以下属性配置项默认值作用ignoreCasefalse是否忽略本地成员名的大小写差异ignoreDeclarationSortfalse是否忽略 import 声明语句之间的排序ignoreMemberSortfalse是否忽略同一声明内多个成员的排序memberSyntaxSortOrder[none, all, multiple, single]四种语法形态的排列顺序4 项必须全部出现但顺序可自定义allowSeparatedGroupsfalse是否只对连续相邻行的 import 声明进行排序校验默认的完整配置写法如下{ sort-imports: [error, { ignoreCase: false, ignoreDeclarationSort: false, ignoreMemberSort: false, memberSyntaxSortOrder: [none, all, multiple, single], allowSeparatedGroups: false }] }需要说明的是从源码看该规则的 schema 定义相当严格lib/rules/sort-imports.jsmemberSyntaxSortOrder必须是恰好包含 4 个元素的数组minItems: 4、maxItems: 4每个元素只能是none、all、multiple、single之一enum且各元素不得重复uniqueItems: true同时additionalProperties: false即不能传入这五个选项之外的未知属性否则配置校验会直接失败。默认配置下的正确 / 错误示例使用默认配置时正确的代码示例/*eslint sort-imports: error*/ import module-without-export.js; import * as bar from bar.js; import * as foo from foo.js; import {alpha, beta} from alpha.js; import {delta, gamma} from delta.js; import a from baz.js; import {b} from qux.js;/*eslint sort-imports: error*/ import a from foo.js; import b from bar.js; import c from baz.js;/*eslint sort-imports: error*/ import foo.js import * as bar from bar.js; import {a, b} from baz.js; import c from qux.js; import {d} from quux.js;/*eslint sort-imports: error*/ import {a, b, c} from foo.js使用默认配置时错误的代码示例每段都会触发报告/*eslint sort-imports: error*/ import b from foo.js; import a from bar.js;/*eslint sort-imports: error*/ import a from foo.js; import A from bar.js;/*eslint sort-imports: error*/ import {c, d} from foo.js; import {a, b} from bar.js;/*eslint sort-imports: error*/ import a from foo.js; import {b, c} from bar.js;/*eslint sort-imports: error*/ import {a} from foo.js; import {b, c} from bar.js;/*eslint sort-imports: error*/ import a from foo.js; import * as b from bar.js;/*eslint sort-imports: error*/ import {b, a, c} from foo.js其中倒数第二段import a ...后跟import * as b ...之所以报错是因为single形态在默认顺序中排在all之后——语法形态顺序错了这与名称a/b无关最后一段则是成员未按字母序排列可由--fix自动修复为{a, b, c}。ignoreCase大小写敏感性控制当ignoreCase为false默认值时大写字母必须始终排在小写字母之前即按 ASCII 序比较如B a。配置{ ignoreCase: false }时错误的代码/*eslint sort-imports: [error, { ignoreCase: false }]*/ import a from bar.js; import B from foo.js; import c from baz.js;配置{ ignoreCase: false }时正确的代码/*eslint sort-imports: [error, { ignoreCase: false }]*/ import B from bar.js; import a from foo.js; import c from baz.js;配置{ ignoreCase: true }时正确的代码忽略大小写后a与B视为同一层级且整体按不区分大小写的顺序排列/*eslint sort-imports: [error, { ignoreCase: true }]*/ import a from bar.js; import B from foo.js; import c from baz.js;配置{ ignoreCase: true }时错误的代码/*eslint sort-imports: [error, { ignoreCase: true }]*/ import B from foo.js; import a from bar.js;从源码看ignoreCase的实现是对参与比较的本地名统一执行toLowerCase()后再比较lib/rules/sort-imports.js成员排序与修复逻辑同样使用getSortableName小写化后的名称作为排序键lib/rules/sort-imports.js。ignoreDeclarationSort跳过声明语句排序当ignoreDeclarationSort为true时规则不再校验 import 声明语句彼此之间的顺序。默认值为false。配置{ ignoreDeclarationSort: false }时错误的代码/*eslint sort-imports: [error, { ignoreDeclarationSort: false }]*/ import b from foo.js import a from bar.js配置{ ignoreDeclarationSort: false }时正确的代码/*eslint sort-imports: [error, { ignoreDeclarationSort: false }]*/ import a from bar.js; import b from foo.js;配置{ ignoreDeclarationSort: true }时正确的代码声明顺序不再受约束/*eslint sort-imports: [error, { ignoreDeclarationSort: true }]*/ import b from foo.js import a from bar.js配置{ ignoreDeclarationSort: true }时错误的代码声明排序被跳过但成员排序仍然生效/*eslint sort-imports: [error, { ignoreDeclarationSort: true }]*/ import {b, a, c} from foo.js;从源码结构看ignoreDeclarationSort为true时整个声明间比较分支previousDeclaration相关逻辑都被跳过lib/rules/sort-imports.js但成员排序校验!ignoreMemberSort分支独立于该开关仍然执行。ignoreMemberSort跳过成员排序当ignoreMemberSort为true时规则忽略multiple形态声明内部多个成员的排序校验。默认值为false。配置{ ignoreMemberSort: false }时错误的代码/*eslint sort-imports: [error, { ignoreMemberSort: false }]*/ import {b, a, c} from foo.js配置{ ignoreMemberSort: false }时正确的代码/*eslint sort-imports: [error, { ignoreMemberSort: false }]*/ import {a, b, c} from foo.js;配置{ ignoreMemberSort: true }时正确的代码成员无序不再报错/*eslint sort-imports: [error, { ignoreMemberSort: true }]*/ import {b, a, c} from foo.js配置{ ignoreMemberSort: true }时错误的代码声明间排序仍然生效/*eslint sort-imports: [error, { ignoreMemberSort: true }]*/ import b from foo.js; import a from bar.js;成员排序在源码中的实现是过滤出所有ImportSpecifier按排序键查找第一个前一个名大于当前名的位置findIndex若存在则在该 specifier 处报告sortMembersAlphabetically消息并带上具体的memberName见 lib/rules/sort-imports.js。memberSyntaxSortOrder自定义语法形态顺序该选项接收一个包含四个预定义元素的数组数组顺序即 import 风格的整体优先级顺序。四种风格分别是none—— 导入模块但不引入导出绑定all—— 导入全部导出绑定import * as ...multiple—— 导入多个成员import {a, b} ...single—— 导入单个成员import a from ...或import {a} from ...。四个元素必须全部出现在数组中但你可以自定义它们的先后次序。默认顺序[none, all, multiple, single]下错误的代码/*eslint sort-imports: error*/ import a from foo.js; import * as b from bar.js;自定义{ memberSyntaxSortOrder: [single, all, multiple, none] }后正确的代码single被提到最前/*eslint sort-imports: [error, { memberSyntaxSortOrder: [single, all, multiple, none] }]*/ import a from foo.js; import * as b from bar.js;自定义{ memberSyntaxSortOrder: [all, single, multiple, none] }后正确的代码all优先且同组内foo早于zoo/*eslint sort-imports: [error, { memberSyntaxSortOrder: [all, single, multiple, none] }]*/ import * as foo from foo.js; import z from zoo.js; import {a, b} from foo.js;在测试中同样可以看到自定义顺序的验证将顺序改为[all, single, multiple, none]后import b from bar.jssingle排在import * as a from foo.jsall之后会报告unexpectedSyntaxOrder见 tests/lib/rules/sort-imports.js证明该顺序确实被用于组间比较。语法顺序错误的报告消息为unexpectedSyntaxOrder其中syntaxA是当前声明的形态、syntaxB是前一条声明的形态lib/rules/sort-imports.js。allowSeparatedGroups按连续行分组校验当allowSeparatedGroups为true时规则只对出现在连续行上的 import 声明进行排序校验。默认值为false。换句话说只要某条 import 声明之后出现了空行、注释行或其他任意语句就会重置声明排序的分组——新的一组从该分隔符之后的 import 重新开始累积。配置{ allowSeparatedGroups: true }时错误的代码三段相邻 import 彼此逆序/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/ import b from foo.js; import c from bar.js; import a from baz.js;配置{ allowSeparatedGroups: true }时正确的代码空行分隔出两个独立分组各自内部有序即可/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/ import b from foo.js; import c from bar.js; import a from baz.js;/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/ import b from foo.js; import c from bar.js; // comment import a from baz.js;/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/ import b from foo.js; import c from bar.js; quux(); import a from baz.js;该选项在源码中的实现对应getNumberOfLinesBetweenlib/rules/sort-imports.js当上一条声明与本条声明之间行数大于 0 时将previousDeclaration重置为null从而开启新的排序分组lib/rules/sort-imports.js。测试用例还覆盖了注释、块级注释、foo()调用、换行位于from之后等边界场景tests/lib/rules/sort-imports.js。注意该选项只影响声明间排序分组multiple声明内部成员的排序校验不受分组影响。When Not To Use Itsort-imports是一种格式化偏好规则不遵守它并不会对代码质量产生负面影响。如果按字母序排列 import并不属于你的编码规范你可以直接关闭该规则例如在配置中不启用它或将严重级别设为off{ rules: { sort-imports: off } }与相关规则的配合在文档元数据中该规则声明了两个相关规则docs/src/rules/sort-imports.md 的 frontmattersort-keys要求对象字面量的键按序排列sort-vars要求同一声明块内的变量按序排列。三者共同构成 ESLint 中局部声明排序的规则家族sort-imports管模块导入、sort-keys管对象键、sort-vars管变量声明。源码注释也印证了这一点——声明间排序使用与sort-vars一致的默认字符串比较方式lib/rules/sort-imports.js。另外该规则的元数据在源码中标记为frozen: truelib/rules/sort-imports.js并可从 docs/src/_data/rules_meta.json 的 sort-imports 条目中查到完整的规则描述信息。小结sort-imports通过语法形态分组 首成员名/别名字母序的双重排序策略帮助团队维护整洁、可扫描的 import 区块。启用规则时你既可以使用默认配置一键开启也可以根据团队偏好调整memberSyntaxSortOrder的四种形态顺序、通过ignoreCase/ignoreDeclarationSort/ignoreMemberSort逐层放宽校验范围或借助allowSeparatedGroups允许用空行/注释/语句将 import 划分为多个独立的分组。需要留意的是--fix只会自动排序同一行内的成员且成员列表含注释时不会修复多行声明之间的顺序仍需手动整理。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考