首页 / 资讯中心 / 文章详情

eslint-plugin-import 的 import/imports-first 规则详解:废弃规则溯源与 import/first 迁移实战

eslint-plugin-import 的 import/imports-first 规则详解:废弃规则溯源与 import/first 迁移实战 ★ FEATURED ARTICLE
开发工具代码质量静态分析【免费下载链接】eslint-plugin-importESLint plugin with rules that help validate proper imports.项目地址https://gitcode.com/gh_mirrors/es/eslint-plugin-import点击查看免费下载import/imports-first是 eslint-plugin-import 中一条确保所有 import 声明出现在其他语句之前的旧规则自 v2.0.0 起已被官方废弃改名为import/first。本文以 imports-first 官方文档 为主体结合 first 规则文档、规则源码 与 测试用例完整讲解该规则的历史沿革、检查逻辑、absolute-first选项、指令directive边界与自动修复行为帮助你理解import 必须置顶这一约定背后的规范动机并平滑迁移到现行规则。规则现状废弃的别名与它的继任者import/imports-first在当前仓库中处于**已废弃deprecated**状态。官方文档第一行即标注❌ This rule is deprecated. / This rule is automatically fixable by the--fixCLI option。其废弃背景记录在 CHANGELOG.md 中v2.0.0 时该规则被重命名为first旧名imports-first作为别名继续可用见 CHANGELOG.md#L843随后在 #1835 中补充了废弃说明与指向first文档的链接CHANGELOG.md#L452。从源码结构看别名机制非常轻量。src/rules/imports-first.js 是一个只有 15 行的薄封装它直接复用./first的完整实现仅重写meta将deprecated置为true并把文档描述改为 Replaced byimport/firstconst first require(./first); const newMeta { ...first.meta, deprecated: true, docs: { category: Style guide, description: Replaced by import/first., url: docsUrl(imports-first, 7b25c1cb95ee18acc1531002fd343e1e6031f9ed), }, }; module.exports { ...first, meta: newMeta };两个名字在 src/index.js 中同时注册first: require(./rules/first), imports-first: require(./rules/imports-first),README 规则总表 也如实呈现了两者差异first标注 可自动修复imports-first标注 与 ❌已废弃。因此新项目应直接使用import/firstimport/imports-first仅用于兼容旧配置。规则行为import 必须出现在所有非 import 语句之前无论旧名还是新名规则的核心理念一致报告任何出现在非 import 语句之后的 import 声明。官方示例import foo from ./foo // some module-level initializer initWith(foo) import bar from ./bar // - reported上述代码中import bar from ./bar位于模块级初始化语句initWith(foo)之后因此被报告。为什么要求 import 置顶一个常被忽略的规范事实是import声明会被提升hoisted即被导入的模块会在文件中穿插的其他语句之前被求值。官方文档强调将所有 import 集中在文件顶部可以避免由规范中这一特性引发的惊喜——比如中间穿插的语句隐式依赖了导入模块的求值顺序。从源码实现看判断逻辑位于 src/rules/first.js 的Program访问器中。它遍历程序体body的每个节点用nonImportCount记录已出现的非 import 语句数量当遍历到ImportDeclaration或TSImportEqualsDeclaration且nonImportCount 0时即产生一条错误const message Import in body of module; reorder to top.;支持 TypeScript 的 import 赋值语法值得注意规则源码同时识别两种节点类型if (node.type ImportDeclaration || node.type TSImportEqualsDeclaration) {即不仅处理标准的import ... from ...也处理 TypeScript 的import y require(bar)形式。测试用例 中专门验证了 TS 场景import y require(bar)与普通 import 混排、且在absolute-first模式下被检查是否违反绝对导入先行的顺序。配置选项absolute-first与disable-absolute-first规则的meta.schemasrc/rules/first.js声明了唯一一个字符串选项取值限定为两个枚举值schema: [ { type: string, enum: [absolute-first, disable-absolute-first], }, ],absolute-first绝对导入必须排在相对导入之前传入absolute-first选项后规则会额外检查任何绝对导入即来自包名/模块名的导入如lodash若出现在相对导入如./bar之后即被报告。官方示例import foo from foo import bar from ./bar import * as _ from lodash // - reported这里lodash是绝对导入却排在了相对导入./bar之后因此被标记。对应的错误消息在源码中单独定义message: Absolute imports should come before relative imports.,源码通过正则/^\./判断导入源是否为相对路径src/rules/first.js的getImportValue与absoluteFirst分支if (absoluteFirst) { if ((/^\./).test(getImportValue(node))) { anyRelative true; } else if (anyRelative) { context.report({ ... }); } }即一旦出现过相对导入后续所有绝对导入都会触发报告。测试用例也覆盖了该场景例如test({ code: import { x } from ./foo; import { y } from bar, options: [absolute-first], errors: 1, });disable-absolute-first显式关闭绝对导入先行disable-absolute-first是默认行为不启用绝对导入顺序检查的显式写法。测试中以该选项声明合法代码test({ code: import { x } from ./foo; import { y } from bar, options: [disable-absolute-first], });即相对导入在前、绝对导入在后此时不报错。若需要更细粒度的导入类型排序builtin / external / parent / sibling / index 等分组官方文档明确指向更强大的import/order。指令Directive的处理边界规则允许严格出现在任何 import 声明之前的指令directive例如use super-mega-strict import { suchFoo } from lame-fake-module-name // no report here此处指令被定义为仅包含一个字符串字面量表达式literal string-valued expression的单条语句。典型的例子是use strict——不过文档也提醒模块module本身始终处于严格模式参见 ECMAScript 规范 strict mode code 相关章节因此在一个同时包含 import 与 export 的文件里看到use strict会是件奇怪的事。其背后理由可追溯至 issue #255 的讨论。源码中的判定逻辑同样严谨src/rules/first.jsfunction isPossibleDirective(node) { return node.type ExpressionStatement node.expression.type Literal typeof node.expression.value string; }只有表达式语句 字符串字面量这一精确形态才被视作指令并跳过if (!anyExpressions isPossibleDirective(node)) return;。注意两个细节仅限最前面anyExpressions一旦被置为true后续即使出现字面量表达式语句也不再豁免仅限 import 之前指令只允许出现在 import 声明之前。测试用例验证了指令出现在 import 之后会被修复挪到末尾tests/src/rules/first.js// 输入 import { x } from foo; use directive; import { y } from bar; // 修复后 import { x } from foo; import { y } from bar; use directive;自动修复Fixer机制与三条准则该规则的meta.fixable为code因此支持 ESLint 的--fix命令行选项。修复器的目标是将主体body中的 import 重新排到文件顶部且遵循三条明确准则官方文档原文绝不改变 import 之间的相对顺序即使设置了absolute-first也不对 import 相互之间重排若某个 import 创建了标识符且该标识符在 import 之前已被模块级代码引用则该 import 不会被重排避免修复后破坏代码语义。这三条准则在源码中逐条落实src/rules/first.js对每个位于非 import 语句之后的 import遍历getDeclaredVariables(context, node)得到的变量引用若存在reference.identifier.range[0] node.range[1]即标识符在 import 之前已被引用则将shouldSort置为false该 import 只报告不修复。修复的文本操作由fixer.insertTextAfter/fixer.removeRange/fixer.replaceTextRange完成errorInfos中被判定可安全排序的节点会被整体剪切并插入到最后一个合法 importlastLegalImp之后若文件顶部原本没有合法 import则插入到body[0]之前并保留原有缩进。修复行为实测测试用例 展示了多 import 重排的完整效果// 输入 import { x } from ./foo; export { x }; import { y } from ./bar; import { z } from ./baz; // 修复后 import { x } from ./foo; import { y } from ./bar; import { z } from ./baz; export { x };再如混合语句场景tests/src/rules/first.js#L67-L79中间的var a 1;与if (true) { x() };保持原位其后的 import 被整体提前// 输入 var a 1; import { y } from ./bar; if (true) { x() }; import { x } from ./foo; import { z } from ./baz; // 修复后 import { y } from ./bar; var a 1; if (true) { x() }; import { x } from ./foo; import { z } from ./baz;可以看到import { y }被移至最前而import { x }与import { z }因为排在if语句之后且其引用x()在 import 之前出现仅被报告、未被移动——这正是第二条修复准则的体现。何时不使用此规则官方文档给出的不使用建议非常直白如果你不介意 import 散落在文件各处就不必启用此规则。当团队风格更自由、或依赖 import 提升特性有意为之例如在模块中部触发副作用导入时可以跳过本规则。需要强调的是absolute-first只是绝对导入先于相对导入这一单维度的弱约束若你需要完整的导入类型分组排序内置模块、外部包、内部路径、父级/同级相对路径等应转向import/order——官方文档称其为 a major step up fromabsolute-first。从 imports-first 到 first迁移与配置建议综合上述分析给出迁移建议替换规则名将配置中的import/imports-first改为import/first。两者共享同一实现src/rules/first.js行为完全一致仅meta.deprecated标记不同可参考 tests/src/package.js 对二者废弃状态的断言。保留选项原absolute-first/disable-absolute-first选项在新规则中继续有效schema 与行为不变。按需升级若只关心import 全部置顶import/first已足够若需要内置模块/外部包/相对路径之间的精细分组排序请使用import/order并配置groups选项。配置示例在 ESLint 配置文件中启用新规则module.exports { plugins: [import], rules: { import/first: error, // 若需要绝对导入先行 import/first: [error, absolute-first], }, };小结import/imports-first是 eslint-plugin-import 中一条被 v2.0.0 废弃的旧规则其职责——确保 import 声明出现在所有其他语句之前——已由import/first完整继承。本文梳理了从废弃别名src/rules/imports-first.js到现行实现src/rules/first.js的完整脉络并结合 测试用例 说明了absolute-first选项、指令边界与三条修复准则。若你的旧配置中仍在使用imports-first只需替换规则名即可无缝迁移若追求更强的导入排序约束则推荐进阶使用import/order。赞分享开发工具代码质量静态分析【免费下载链接】eslint-plugin-importESLint plugin with rules that help validate proper imports.项目地址https://gitcode.com/gh_mirrors/es/eslint-plugin-import点击查看免费下载相关推荐eslint-plugin-import 的 import/first 规则强制 import 置顶与自动修复实践eslint plugin import 的 import/first 规则强制 import 置顶与自动修复实践 导读 import/first 是 esl开发工具代码质量静态分析eslint-plugin-import 的 no-import-module-exports 规则禁止 import 与 CommonJS 导出混用eslint plugin import 的 no import module exports 规则禁止 import 与 CommonJS 导出混用 导读开发工具代码质量静态分析eslint-plugin-import 的 import/no-amd 规则在 ES6 迁移中拦截 AMD require/define 调用eslint plugin import 的 import/no amd 规则在 ES6 迁移中拦截 AMD require / define 调用 导读 i开发工具代码质量静态分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站