<p>Node.js 从 v14.13.0 起原生支持 subpath imports,通过 package.json 的 "imports" 字段实现内部模块别名导入;它以 # 开头声明导入映射,仅限本包内使用,需配合 "type": "module",提升封装性与运行时一致性。</p>

Node.js 从 v14.13.0 开始原生支持子路径导入(subpath imports),无需额外工具或打包器,通过 package.json 中的 "imports" 字段即可实现安全、明确、可静态分析的内部模块别名导入。
什么是 subpath imports?
它是一种在 package.json 中声明模块导入映射的机制,用于将形如 import "pkg/subpath" 的导入语句,解析为项目内具体的相对路径(如 ./src/utils/helpers.js),同时禁止未显式声明的子路径访问(即“深度导入”被默认封禁),提升封装性和可维护性。
与旧式的 exports 字段不同,imports 专用于当前包内部的导入重写(只影响 import 和 require() 在本包内的使用),不对外暴露。
如何配置 imports 字段?
在项目根目录的 package.json 中添加 "imports" 字段,值为一个对象,键是导入说明符(支持模式匹配),值是对应解析路径(支持相对路径或内置模块):
立即学习“Java免费学习笔记(深入)”;
- 键必须以
#开头(推荐前缀,增强语义和避免与真实包名冲突) - 支持通配符
*,例如"#utils/*": "./src/utils/*" - 路径值需以
./、../或node:开头,否则会被视为外部包 - 必须与
"type": "module"配合使用(ESM 模式)
示例配置:
{
"type": "module",
"imports": {
"#root/*": "./src/*",
"#utils": "./src/utils/index.js",
"#api/client": "./src/api/client.mjs",
"#config": "./src/config/default.js"
}
}
之后即可在项目中这样导入:
import { debounce } from '#utils';
import api from '#api/client';
import config from '#config';
注意事项与常见问题
-
仅限本包内使用:其他项目
import 'your-pkg/#utils'不生效,imports不参与跨包解析 -
不兼容 CommonJS require(除非用 ESM 加载器或
createRequire),建议统一使用 ESM -
路径必须存在且可解析:若
./src/utils/index.js不存在,运行时会抛出ERR_MODULE_NOT_FOUND -
不能覆盖内置模块名:如
"#fs": "node:fs/promises"是允许的,但"fs": "node:fs/promises"(无#)会报错 -
与 exports 字段协同使用更规范:用
exports控制对外暴露,用imports管理内部组织
对比其他方案(如 tsconfig paths / vite alias)
imports 是 Node.js 原生标准,不依赖 TypeScript 编译、构建工具或运行时插件,所有符合规范的 Node 环境(v14.13+)均可直接识别。而 tsconfig.json 的 paths 仅作用于 TS 类型检查和编译,Vite/Webpack 的 alias 属于构建时重写,均无法保证运行时行为一致。使用 imports 能真正实现“所写即所运”。










