import/extensions 限制
它的作用
某些文件解析算法允许你在导入路径中省略文件扩展名。 例如,Node 解析器(目前还不支持 ESM/import)可以将 ./foo/bar 解析为绝对路径 /User/someone/foo/bar.js,因为 .js 扩展名在 CJS 中默认会被自动解析。 根据所使用的解析器,你可以配置更多扩展名以实现自动解析。 为了在代码库中保持文件扩展名的一致性使用,此规则可强制或禁止使用特定的文件扩展名。
为什么这是个问题?
基于 ESM 的文件解析算法(如 Vite 提供的)建议显式指定文件扩展名,以提升性能。
示例
此规则的 错误 示例:
当配置设置为 "always" 时,以下模式被视为问题:
import foo from "./foo";
import bar from "./bar";
import Component from "./Component";
import foo from "@/foo";当配置设置为 "never" 时,以下模式被视为问题:
import foo from "./foo.js";
import bar from "./bar.json";
import Component from "./Component.jsx";
import express from "express/index.js";此规则的 正确 示例:
当配置设置为 "always" 时,以下模式不被视为问题:
import foo from "./foo.js";
import bar from "./bar.json";
import Component from "./Component.jsx";
import * as path from "path";
import foo from "@/foo.js";当配置设置为 "never" 时,以下模式不被视为问题:
import foo from "./foo";
import bar from "./bar";
import Component from "./Component";
import express from "express/index";
import * as path from "path";按扩展名配置示例:
// 配置:{ "vue": "always", "ts": "never" }
import Component from "./Component.vue"; // ✓ 正确 - .vue 配置为 "always"
import utils from "./utils"; // ✓ 正确 - .ts 配置为 "never"
import styles from "./styles.css"; // ✓ 正确 - .css 未配置,被忽略
// 配置:["ignorePackages", { "js": "never", "ts": "never" }]
import foo from "./foo"; // ✓ 正确 - 无扩展名
import bar from "lodash/fp"; // ✓ 正确 - 包导入,被忽略(ignorePackages 设置为 true)配置
此规则接受三种类型的配置:
- 全局规则(字符串):"always"、"never" 或 "ignorePackages"
{
"rules": {
// 这将要求所有导入都带有扩展名,*包括包导入*
// 例如 `import React from 'react';` 将被禁止。
// 通常在使用 `always` 时,应始终将 `ignorePackages` 设置为 `true`。
"import/extensions": ["error", "always"],
},
}- 按扩展名规则(对象):
{ "js": "always", "jsx": "never", ... }
{
"rules": {
"import/extensions": [
"error",
// 按扩展名规则:
// 要求 .js 导入带有扩展名,禁止 .ts 导入带有扩展名
{ "js": "always", "ts": "never", "ignorePackages": true },
],
},
}- 组合形式(数组):
["error", "always", { "js": "never" }]或["error", { "js": "always" }]
{
"rules": {
"import/extensions": [
"error",
"always", // 默认情况下,要求所有导入都带有扩展名
{
"ts": "never", // 覆盖全局值,对特定文件类型导入禁止使用扩展名
"ignorePackages": true,
},
],
},
}默认行为(无配置):所有导入——无论何种类型——均通过验证。 未配置的文件扩展名将被忽略,以避免误报。
此规则接受一个包含以下属性的配置对象:
checkTypeImports
type: boolean
default: false
是否在强制执行扩展名规则时检查类型导入。
// 如果 checkTypeImports 为 `false`,我们不关心这些导入是否有文件扩展名,
// 两者始终都被允许:
import type { Foo } from "./foo";
import type { Foo } from "./foo.ts";ignorePackages
type: boolean
default: false
是否在强制执行扩展名规则时忽略包导入。
IMPORTANT
将此规则设置为 always 时,还应将 ignorePackages 设置为 true。 否则,没有扩展名的包导入(如 import React from 'react';) 将被禁止,这不符合预期且无法修复。
一个布尔选项(非按扩展名),用于使包导入免于 "always" 规则的约束。
可在配置对象中设置:["error", "always", { "ignorePackages": true }]
旧版简写:["error", "ignorePackages"] 等价于 ["error", "always", { "ignorePackages": true }]
- 使用 "always":当为
true时,包导入(如lodash、@babel/core)不需要扩展名 - 使用 "never":此选项无效;包导入仍然禁止使用扩展名
示例:["error", "always", { "ignorePackages": true }] 允许 import foo from "lodash",但要求 import bar from "./bar.js"
pathGroupOverrides
type: array
default: []
针对特定导入规范的路径组覆盖。
用于自定义导入协议(如 monorepo 工具、自定义解析器)的模式-操作对数组。 每个覆盖项包含:{ "pattern": "<glob-pattern>", "action": "enforce" | "ignore" }
模式匹配:使用 glob 模式(*、**、{a,b})匹配导入规范。 请注意,模式匹配由 Rust 的 fast-glob 库完成,因此可能与原始 ESLint 规则使用的 JavaScript glob 库有所不同。
操作:
"enforce":应用正常的扩展名验证(遵守全局/按扩展名规则)"ignore":跳过匹配导入的所有扩展名验证
优先级:首个匹配的模式生效。
示例:
{
"pattern": "rootverse{*,*/**}",
"action": "ignore"
}匹配来自 rootverse+debug:src、rootverse+bfe:src/symbols 等的导入,并忽略其是否带有扩展名。
pathGroupOverrides[n]
type: object
pathGroupOverrides[n].action
type: "enforce" | "ignore"
路径组覆盖的操作。
决定如何验证匹配的特定导入规范的文件扩展名。
"enforce"
对匹配的导入强制执行扩展名验证(根据配置要求扩展名)。
"ignore"
完全忽略匹配的导入(跳过所有扩展名验证)。
pathGroupOverrides[n].pattern
type: string
用于匹配导入规范的 glob 模式。此模式使用 Rust 的 fast-glob 库进行匹配。
如何使用
要通过配置文件或 CLI 启用此规则,可以使用:
{
"plugins": ["import"],
"rules": {
"import/extensions": "error"
}
}oxlint --deny import/extensions --import-plugin