import.meta 是 ES 模块(ESM)特有的元数据对象,提供当前模块的上下文信息,是 ES 标准的一部分(ES2020 引入),Node.js 从 v12.2.0 开始支持(需启用 ESM,v14.13.0 及以上无需实验性标志)。本文从核心概念、Node.js 专属特性、使用场景、注意事项等维度全面解析。
一、基础前提:启用 ES 模块
Node.js 默认使用 CommonJS 模块,import.meta 仅在 ESM 中可用,需通过以下方式启用 ESM:
- 文件后缀为
.mjs; package.json中配置"type": "module";- 执行时通过
--input-type=module运行字符串代码(如node --input-type=module -e "console.log(import.meta)")。
二、import.meta 核心特性
1. 本质:模块级别的只读对象
import.meta是每个 ES 模块独有的实例,不同模块的import.meta互不相同;- 不可赋值(
import.meta = {}会报错),但对象内部属性可修改(如import.meta.url = 'xxx'仅影响当前模块的该属性); - 仅在模块顶层可用,不能在函数、类等作用域内直接访问(需闭包捕获)。
2. 标准属性:import.meta.url(跨平台通用)
import.meta.url 是 import.meta 最核心的属性,返回当前模块的文件 URL 路径(而非本地文件系统路径),格式为 file:// 开头(本地文件)或 http:///https://(远程模块)。
示例:基础使用
// 假设文件路径:/user/project/index.mjs
console.log(import.meta.url);
// 输出:file:///user/project/index.mjs(mac/Linux)
// 输出:file:///C:/user/project/index.mjs(Windows,注意盘符大写)
关键转换:URL 转本地文件路径
Node.js 提供 node:url 模块的 fileURLToPath 方法,可将 import.meta.url 转为操作系统兼容的本地路径:
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
// 当前文件的本地路径
const __filename = fileURLToPath(import.meta.url);
// 当前文件所在目录(替代 CommonJS 的 __dirname)
const __dirname = dirname(__filename);
console.log(__filename); // /user/project/index.mjs(mac/Linux)
console.log(__dirname); // /user/project
console.log(join(__dirname, 'utils', 'helper.mjs')); // 拼接路径
三、Node.js 专属扩展属性
Node.js 为 import.meta 扩展了多个平台特有的属性,补充模块运行时的上下文信息:
1. import.meta.resolve(v18.19.0+/v20.0.0+ 稳定)
异步方法,用于解析模块路径(类似 require.resolve,但适配 ESM),返回解析后的模块 URL。
语法:
const resolvedUrl = await import.meta.resolve(specifier[, parentURL]);
specifier:要解析的模块路径(相对/绝对/裸模块);parentURL:可选,解析的基准 URL(默认是当前模块的import.meta.url)。
示例:
// 解析相对模块
const utilsUrl = await import.meta.resolve('./utils.mjs');
console.log(utilsUrl); // file:///user/project/utils.mjs
// 解析裸模块(如 npm 包)
const lodashUrl = await import.meta.resolve('lodash');
console.log(lodashUrl); // file:///user/project/node_modules/lodash-es/lodash.mjs
// 自定义基准路径
const customUrl = await import.meta.resolve('helper.mjs', 'file:///user/project/lib/');
2. import.meta.dirname & import.meta.filename(v20.11.0+ 稳定)
Node.js 提供的语法糖,直接替代手动转换的 __dirname/__filename,无需引入 url/path 模块。
示例:
// /user/project/app.mjs
console.log(import.meta.filename); // /user/project/app.mjs(本地路径,无 file://)
console.log(import.meta.dirname); // /user/project
3. import.meta.main(判断模块是否为入口)
返回布尔值:true 表示当前模块是 Node.js 进程的入口文件,false 表示模块被其他模块导入。
示例:
// app.mjs
if (import.meta.main) {
console.log('我是入口模块');
// 执行入口逻辑
} else {
console.log('我是被导入的模块');
}
// 运行 node app.mjs → 输出「我是入口模块」
// 其他模块 import './app.mjs' → 输出「我是被导入的模块」
替代 CommonJS 的
require.main === module。
4. import.meta.resolveSync(同步版本,v18.19.0+/v20.0.0+ 稳定)
import.meta.resolve 的同步版本,适用于无需异步的场景:
const path = import.meta.resolveSync('./config.mjs');
console.log(path);
5. 实验性属性(谨慎使用)
import.meta.url.slice(7):手动截取file://前缀(不推荐,建议用fileURLToPath);import.meta.env:非 Node.js 原生属性,通常由构建工具(Vite、Webpack)注入环境变量,Node.js 原生不支持。
四、核心使用场景
1. 替代 CommonJS 的 __dirname/__filename
ESM 中移除了 __dirname/__filename,需通过 import.meta 实现相同功能:
// 兼容低版本 Node.js(v20.11.0 以下)
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// v20.11.0+ 简化写法
const { dirname, filename } = import.meta;
2. 动态加载模块
结合 import() 动态导入,基于 import.meta.url 解析相对路径:
// 动态加载当前目录下的模块
async function loadModule(moduleName) {
const moduleUrl = new URL(`./${moduleName}.mjs`, import.meta.url).href;
const module = await import(moduleUrl);
return module;
}
loadModule('utils').then(utils => utils.doSomething());
3. 读取模块所在目录的文件
结合 fs/promises 读取本地文件,基于 import.meta.dirname 拼接路径:
import { readFile } from 'node:fs/promises';
async function readConfig() {
// v20.11.0+
const configPath = `${import.meta.dirname}/config.json`;
// 低版本替代:join(__dirname, 'config.json')
const content = await readFile(configPath, 'utf8');
return JSON.parse(content);
}
4. 多环境模块入口判断
通过 import.meta.main 实现模块的「复用+入口」双模式:
// utils.mjs
export function add(a, b) {
return a + b;
}
// 仅作为入口时执行测试
if (import.meta.main) {
console.log('测试 add 方法:', add(1, 2)); // 3
}
5. 解析第三方模块的真实路径
通过 import.meta.resolve 查看 npm 包的实际安装路径:
async function getPackagePath(pkgName) {
const url = await import.meta.resolve(pkgName);
// 转为本地路径
const path = fileURLToPath(url);
console.log(`${pkgName} 的路径:`, path);
}
getPackagePath('express'); // 输出 express 入口文件的本地路径
五、注意事项与坑点
1. 仅支持 ESM,CommonJS 不可用
如果在 .cjs 文件或未启用 ESM 的 .js 文件中访问 import.meta,会直接报错 ReferenceError: import is not defined。
2. import.meta.url 是 URL 而非本地路径
- Windows 系统中,
import.meta.url格式为file:///C:/xxx/xxx,直接拼接路径会导致错误,必须用fileURLToPath转换; - 远程模块(如
import 'https://cdn.example.com/module.mjs')的import.meta.url是远程 URL,无本地路径。
3. 模块顶层 await 不影响 import.meta
即使模块使用顶层 await,import.meta 仍可正常访问:
// 合法
const resolved = await import.meta.resolve('./a.mjs');
console.log(import.meta.url);
4. import.meta.main 与子进程/工作线程
- 子进程(
child_process)中执行的模块,import.meta.main为true(子进程独立入口); - 工作线程(
worker_threads)中,import.meta.main取决于线程入口是否为该模块。
5. 兼容性问题
| 属性 | 最低 Node.js 版本 | 稳定性 |
|---|---|---|
import.meta.url | v12.2.0 | 稳定 |
import.meta.main | v14.0.0 | 稳定 |
import.meta.resolve | v18.19.0/v20.0.0 | 稳定 |
import.meta.dirname/filename | v20.11.0 | 稳定 |
六、与 CommonJS 等效对比
| CommonJS 特性 | ESM 等效实现(import.meta) |
|---|---|
__filename | import.meta.filename(v20.11+)或 fileURLToPath(import.meta.url) |
__dirname | import.meta.dirname(v20.11+)或 dirname(fileURLToPath(import.meta.url)) |
require.main === module | import.meta.main |
require.resolve() | import.meta.resolve()/import.meta.resolveSync() |
七、总结
import.meta 是 ESM 模块的核心元数据工具,Node.js 基于标准扩展了实用属性,核心价值在于:
- 替代 CommonJS 的
__dirname/__filename/require.resolve等特性; - 提供模块上下文信息(入口判断、路径解析);
- 适配 ESM 的模块化规范,支持动态路径解析。
使用建议:
- 优先使用稳定属性(如
url、main、dirname),避免实验性 API; - 低版本 Node.js 需通过
fileURLToPath手动转换路径; - 结合
import()动态导入时,用new URL(relativePath, import.meta.url)解析路径,避免相对路径陷阱。
1008

被折叠的 条评论
为什么被折叠?



