先记住这个答案
import.meta.resolve() 接收一个模块说明符,按 import 语句相同的规则把它解析成完整的 URL 字符串返回。它只做解析,不下载、不执行模块。和 import 的关系就是:import 先解析、再加载、再执行,import.meta.resolve 只做第一步。所以它能看到 import map、package.json 的 exports 这些规则的最终结果。
- 只解析模块 URL,不加载模块
- 同步返回字符串,不是 Promise
- 裸说明符也可按当前环境解析
- 相对路径不检查文件是否存在,找不到的包会抛错
在 Node.js 里看看它返回什么
假设项目里装了一个包 pkg,它的 package.json 用 exports 把入口指向了 dist/index.mjs。
// /app/main.mjs
console.log(import.meta.resolve('./utils.mjs'))
// file:///app/utils.mjs
console.log(import.meta.resolve('pkg'))
// file:///app/node_modules/pkg/dist/index.mjs(按 exports 解析)
console.log(import.meta.resolve('./not-exist.mjs'))
// file:///app/not-exist.mjs,相对路径不检查文件是否存在
import.meta.resolve('no-such-pkg')
// 抛出 ERR_MODULE_NOT_FOUND,找不到包时无法算出 URL返回的是字符串,不是 Promise。早期 Node.js 实现过异步版本,后来和浏览器统一成了同步。第二行很能说明问题:你不需要知道 pkg 的文件结构,它会按包自己声明的 exports 找到真正的入口。
相对路径那一行说明它只是在「算地址」,文件存不存在要等真正 import 时才知道。裸说明符不一样,找不到包就连地址都算不出来,所以会抛错。
什么时候需要它
平时写 import 用不到它。需要的场景是:你要的是一个模块的地址,而不是模块本身。
- 把地址交给别的 API
- 典型例子是创建 Worker:
new Worker(import.meta.resolve("pkg/worker.js"), { type: "module" })。Worker 的构造函数只接受 URL,你又希望这个地址跟着依赖版本、import map 走,用它最合适。 同样的思路也适用于加载 WASM 文件、给<link rel="modulepreload">生成地址、在 Service Worker 里预缓存模块。浏览器里如果页面配了 import map,import.meta.resolve("vue")返回的就是映射后的 CDN 地址,调试映射有没有写对也很方便。
容易答错的地方
- 以为它会加载模块
- 它不发网络请求,也不执行模块代码,调用多少次都没有副作用。想拿到模块内容要用
import()。 - 以为它等价于
new URL(path, import.meta.url) - 对相对路径来说两者结果一样。但
new URL只是做 URL 拼接,new URL("vue", import.meta.url)会得到当前目录下一个叫vue的文件地址,完全错误。import.meta.resolve才会按包解析、查 import map。 - 以为它能在 CommonJS 里用
import.meta只存在于 ES 模块中,CommonJS 文件里写它是语法错误。CommonJS 里对应的是require.resolve(),它返回的是文件系统路径,不是 URL,并且会检查文件是否存在。
面试官还会怎么问?
和 require.resolve 有什么区别?
require.resolve 走的是 CommonJS 解析规则,返回文件路径字符串,文件不存在会抛错。import.meta.resolve 走 ESM 规则,返回 file:// 开头的 URL,相对路径不检查存在性。两者对同一个包可能给出不同结果,因为 exports 里可以给 import 和 require 配置不同的入口。
解析结果怎么转成文件路径?
在 Node.js 里用 node:url 模块的 fileURLToPath(),把 file:///app/a.mjs 转成 /app/a.mjs,Windows 上还会正确处理盘符。不要自己用字符串截掉 file://,遇到中文路径和空格会被百分号编码坑到。
浏览器里能用吗?
主流浏览器都已支持,并且会遵守页面上的 import map。老环境不支持时,相对路径可以退回 new URL(path, import.meta.url) 的写法。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。