eslint-plugin-unicorn `import-style` 规则完全指南:按模块强制执行统一的 import 风格
2026/9/18 23:49:10 网站建设 项目流程

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 的utilpromisifycallbackifyinspect……),此时强制使用解构式命名导入(named import)反而更利于 tree-shaking 与按需使用;
  • 有些模块内部函数高度相似、几乎都会被用到,例如pathjoinresolvedirname……),此时默认导入(default import)更简洁统一。

import-style正是为此而生:它允许你为每个模块单独指定允许的导入风格,对不在配置范围内的模块不做任何限制。

该规则在项目中的地位:它属于 eslint-plugin-unicorn 的众多规则之一(见 规则注册文件),meta.docs.recommended标记为unopinionated(源码 rules/import-style.js#L398),因此同时被recommendedunopinionated两套预设配置启用(对应 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 写法
unassignedimport 'foo'require('foo')
defaultimport path from 'path'const path = require('path')(含const {default: path} = require('path')
namespaceimport * as path from 'path'const path = require('path')(整对象赋值)
namedimport {inspect} from 'util'const {inspect} = require('util')

需要特别说明的是defaultnamespacerequire语境下的重叠:由于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:fsnode: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:utilutil使用同一套样式,配置时按裸模块名(utilpath)书写即可。

这一机制由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'))的检查。对应ImportExpressionVariableDeclarator监听器(rules/import-style.js#L227-L259)。

动态导入的样式判定规则:裸import('foo')视为unassigned风格;const {x} = await import('foo')视为namedconst {default: x} = await import('foo')视为defaultconst 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'语句的检查(默认关闭)。对应ExportAllDeclarationExportNamedDeclaration监听器(rules/import-style.js#L261-L281)。判定规则:export * from 'foo'视为namespace风格,export {x} from 'foo'视为namedexport {default} from 'foo'视为default。不含from的纯export {foo}不会触发检查(test/import-style.js#L160-L163)。

checkRequire

类型:boolean,默认true

传入"checkRequire": false可完全关闭对require调用的检查。对应CallExpressionVariableDeclarator监听器(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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询