eslint-plugin-unicornimport-style规则完全指南:按模块强制执行统一的 import 风格
【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn
本篇技术指南围绕 eslint-plugin-unicorn 的import-style规则展开,系统讲解其 4 种导入风格、node:协议匹配机制、styles等全部 6 个配置项,并结合 规则源码 与 测试用例 从源码级剖析其判定逻辑与边界行为。读完你将能够独立完成规则配置、理解报错含义,并能在自己的 ESLint 项目中落地一套"按模块差异化"的导入风格规范。
规则背景:为什么需要按模块区分导入风格
在实际项目中,不同模块的"最佳导入方式"往往不同:
- 有些模块包含大量彼此无关的函数,例如 Node.js 的
util(promisify、callbackify、inspect……),此时强制使用解构式命名导入(named import)反而更利于 tree-shaking 与按需使用; - 有些模块内部函数高度相似、几乎都会被用到,例如
path(join、resolve、dirname……),此时默认导入(default import)更简洁统一。
import-style正是为此而生:它允许你为每个模块单独指定允许的导入风格,对不在配置范围内的模块不做任何限制。
该规则在项目中的地位:它属于 eslint-plugin-unicorn 的众多规则之一(见 规则注册文件),meta.docs.recommended标记为unopinionated(源码 rules/import-style.js#L398),因此同时被recommended与unopinionated两套预设配置启用(对应 readme 规则表中的 ✅ ☑️ 标记,见 readme.md)。规则类型为problem,意味着它报告的是代码中确实存在的风格不一致问题。
适用前提:本规则基于 JavaScript AST 静态分析,默认仅启用
js/js语言(见 rules/import-style.js#L403);TypeScript 场景下对import type有特殊处理(详见后文)。需要 ESLint 新版 API(context.on)支持的运行环境。
规则定义的 4 种导入风格
规则将导入方式抽象为 4 种风格,每种风格同时覆盖 ESM 与 CommonJS 两种写法:
| 风格 | ESM 写法 | CommonJS 写法 |
|---|---|---|
unassigned | import 'foo' | require('foo') |
default | import path from 'path' | const path = require('path')(含const {default: path} = require('path')) |
namespace | import * as path from 'path' | const path = require('path')(整对象赋值) |
named | import {inspect} from 'util' | const {inspect} = require('util') |
需要特别说明的是default与namespace在require语境下的重叠:由于require无法预先判断目标模块是编译后的 ES Module(带default键)还是 CommonJS 模块,源码 rules/import-style.js#L193-L200 中做了一次放宽处理——当某模块仅允许default时,const path = require('path')这种 namespace 式赋值同样被视为合法。测试中const x = require('default')被判定为 valid 即印证了这一点(test/import-style.js#L121)。
基础示例:默认样式下的检查行为
// ❌ util 默认只允许 named 导入 const util = require('node:util'); // ✅ const {promisify} = require('node:util');// ❌ 默认导入 util 被禁止 import util from 'node:util'; // ❌ 命名空间导入 util 同样被禁止 import * as util from 'node:util'; // ✅ import {promisify} from 'node:util';// ❌ path 默认只允许 default 导入,命名空间导入被禁止 import * as path from 'node:path'; // ✅ import path from 'node:path';对应到测试用例,import util from 'node:util'、import * as util from 'node:util'、const util = require('node:util')、require('node:util')等均为 invalid,而import {inspect} from 'node:util'、const {inspect} = require('node:util')、import path from 'node:path'等均为 valid(见 test/import-style.js#L166-L197 与 test/import-style.js#L717-L760)。
未配置的模块(如node:fs、node:unknown)不受影响,import fs from 'node:fs'、import * as fs from 'node:fs'、import {readFile} from 'node:fs'均合法(test/import-style.js#L252-L297)。
默认样式(defaultStyles)
内置默认样式在源码中以defaultStyles常量定义(rules/import-style.js#L128-L138),仅覆盖 3 个模块:
chalk—— 仅允许default导入path—— 仅允许default导入util—— 仅允许named导入
规则只对出现在styles配置与默认样式中的模块生效,其余导入一概不受影响。
node:协议匹配机制
带node:协议的导入会剥离协议前缀后再匹配样式:node:util与util使用同一套样式,配置时按裸模块名(util、path)书写即可。
这一机制由getModuleStyleName函数实现(rules/import-style.js#L122-L125):模块名以node:开头时,截掉该前缀作为查找键。测试也验证了继承行为:
- 为
util配置{default: true}后,node:util变为允许named or default(test/import-style.js#L801-L821); - 若同时显式声明
{default: true, named: false},则node:util仅允许default(test/import-style.js#L822-L844); - 而
require('ut' + 'il')、require('node:' + 'util')这类非常量字符串也能被识别(常量折叠后匹配),见 test/import-style.js#L751-L760。
Options 完整配置指南
styles
类型:object。用于按模块扩展(或收窄)默认导入样式。每个模块的值既可以是false(完全解除限制),也可以是形如{named: true}的布尔对象。
示例:以下配置解除了util的全部限制,同时为path额外开放named(默认default仍然有效):
'unicorn/import-style': [ 'error', { styles: { util: false, path: { named: true, }, }, }, ]几点重要语义:
- 值为
false表示"任意风格皆可":测试中styles: {util: false}后,import util from "node:util"、import * as util2 from "node:util"、import {foo} from "node:util"全部合法(test/import-style.js#L309-L322)。 - 布尔对象中显式
false的键会被合并覆盖:styles: {util: {named: false}}会覆盖默认的{named: true},结果是 util 无任何允许风格但不会被视为"禁用模块"而报 banned 错误,而是直接放行(test/import-style.js#L323-L337)。 - 请勿将某模块的全部风格设为
false:这会使该模块进入"banned"状态,报出importStyleBanned错误("All import styles are disabled for module ... Use theno-restricted-importsrule to disallow a module.")。该判定由源码中bannedModules集合完成(rules/import-style.js#L160-L164),建议改用 ESLint 自带的no-restricted-imports规则彻底禁用某个模块。 - 样式合并规则:开启
extendDefaultStyles时,用户配置与默认样式按"默认样式 → 用户配置"顺序浅合并(rules/import-style.js#L155-L158),用户可打开默认未开放的风格,也可显式关闭默认已开放的风格。 - 被允许的多种风格在报错信息中通过
Intl.ListFormat以英文析取连词展示,例如allowedStyles: 'named, namespace, or default'(见 test/import-style.js#L795)。
extendDefaultStyles
类型:boolean,默认true。
传入"extendDefaultStyles": false可完全抛弃默认样式表,仅使用styles中显式配置的内容。源码中当该值为false时,styles不再与defaultStyles合并(rules/import-style.js#L155-L158)。典型场景:团队想从头自定义全部模块样式,不希望被chalk/path/util的默认规则干扰。
checkImport
类型:boolean,默认true。
传入"checkImport": false可完全关闭对静态 import 语句的检查(import ... from 'foo'与import 'foo')。对应源码中的ImportDeclaration监听器(rules/import-style.js#L218-L225)。测试中import 'chalk'在checkImport: false下为 valid(test/import-style.js#L206-L210)。
checkDynamicImport
类型:boolean,默认true。
传入"checkDynamicImport": false可完全关闭对动态导入(await import('foo')及裸import('foo'))的检查。对应ImportExpression与VariableDeclarator监听器(rules/import-style.js#L227-L259)。
动态导入的样式判定规则:裸import('foo')视为unassigned风格;const {x} = await import('foo')视为named;const {default: x} = await import('foo')视为default;const x = await import('foo')与const [x] = await import('foo')视为namespace(对应 getActualAssignmentTargetImportStyles 的解析逻辑,测试见 test/import-style.js#L632-L640)。测试中const {red} = await import('chalk')在checkDynamicImport: false下为 valid(test/import-style.js#L212-L220)。
checkExportFrom
类型:boolean,默认false。
传入"checkExportFrom": true可开启对export ... from 'foo'语句的检查(默认关闭)。对应ExportAllDeclaration与ExportNamedDeclaration监听器(rules/import-style.js#L261-L281)。判定规则:export * from 'foo'视为namespace风格,export {x} from 'foo'视为named,export {default} from 'foo'视为default。不含from的纯export {foo}不会触发检查(test/import-style.js#L160-L163)。
checkRequire
类型:boolean,默认true。
传入"checkRequire": false可完全关闭对require调用的检查。对应CallExpression与VariableDeclarator监听器(rules/import-style.js#L283-L323)。规则只识别单参数、非可选链的require(...)调用,且要求其处于表达式语句或变量声明初始化位置;require(1, 2, 3)、require(variable)(非常量参数)、const x = require('unassigned').x等均不会被检查(test/import-style.js#L299-L302)。非空的数组解构(const [x] = require('foo'))不被识别为任何风格,同样跳过检查。
报错信息与类型检查(TypeScript)特例
规则定义了两条消息(rules/import-style.js#L4-L9):
importStyle:"Use {{allowedStyles}} import for module{{moduleName}}."importStyleBanned:"All import styles are disabled for module{{moduleName}}. Use theno-restricted-importsrule to disallow a module."
TypeScript 场景下:
- 纯类型导入不受影响:
import type chalk from 'chalk'、import type {x} from 'named'、import {type ChalkInstance} from 'chalk'均不报错(test/import-style.js#L848-L870),因为源码对importKind === 'type'及 type 修饰的 specifier 直接跳过(rules/import-style.js#L13-L16 与 rules/import-style.js#L38-L40)。 - 混合导入按运行时代码判定:
import {type ChalkInstance, red} from 'chalk'因存在非 type 的red而按 named 判定,最终报default错误(test/import-style.js#L872-L882)。 - banned 模块的类型导入同样报错:
import type {Foo} from 'banned'与import {type Foo} from 'banned'都会触发importStyleBanned(test/import-style.js#L883-L902)。
规则 Schema 与配置校验
规则的配置项定义于 JSON Schema(rules/import-style.js#L326-L387),可作为编写配置时的约束参考:
- 选项为单元素数组,元素为对象且不允许额外属性(
additionalProperties: false),共 6 个布尔/对象字段; styles的值类型通过definitions.styles定义为false或布尔对象(booleanObject,其属性值均为boolean);- 全部选项都有默认值兜底(
defaultOptions: [{}]),意味着不传任何参数时规则以默认样式表 + 全量检查(除checkExportFrom外)运行。
推荐配置:推荐的完整启用示例
将以下配置加入你的 ESLint 配置文件即可启用该规则并覆盖全部常用选项:
'unicorn/import-style': [ 'error', { styles: { util: false, // 取消对 util 的默认 named 限制 path: { named: true, // path 除 default 外额外允许 named }, 'node:fs': { default: true, // 新增模块:node:fs 仅允许默认导入(注意 node: 前缀按裸名匹配亦可) }, }, extendDefaultStyles: true, checkImport: true, checkDynamicImport: true, checkExportFrom: true, // 如需一并检查 export ... from checkRequire: true, }, ]如果你正在使用本仓库自带的recommended预设(见 configs/flat-config-base.js 及 readme.md),该规则已默认启用、开箱即用;此时只需要按需通过styles扩展模块范围即可。若你的代码库风格与默认预设冲突,可使用extendDefaultStyles: false完全接管样式表,实现团队自定义的导入规范。
小结
import-style通过"模块名 → 允许风格集合"的映射模型,把散落各处的导入风格约束收敛为可配置、可解释、可测试的规则:默认样式覆盖chalk/path/util三个高频模块,node:协议自动归一化匹配,6 个开关分别控制 import、动态 import、export-from、require 四类语法节点的检查,并完整支持 TypeScript 类型导入豁免。理解其判定逻辑后,你既可以直接使用默认行为,也可以通过styles与各开关精细定制属于自己的导入规范。
【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考