esbuild 打包后为什么 import.meta.url 变成 undefined 了?

小胜洋 阅读 11

我用 esbuild 打包一个使用了 import.meta.url 的 ESM 模块,结果在浏览器里运行时报错说 import.meta 是 undefined。明明开发时直接用原生 ESM 是没问题的,是不是 esbuild 默认不支持这个语法?

我试过加 --platform=node--platform=browser 都不行。代码大概是这样:

const __dirname = new URL('.', import.meta.url).pathname;
console.log('当前目录:', __dirname);
我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
UI雯清
UI雯清 Lv1
你这个问题是 esbuild 默认打包成 IIFE 格式导致的,IIFE 根本不是 ESM 模块,import.meta 当然不存在。

加上 --format=esm 就完事了:

esbuild input.js --format=esm --bundle --outfile=output.js


如果用的是 API 方式调用,配置里加 format: 'esm'

await esbuild.build({
entryPoints: ['input.js'],
format: 'esm',
bundle: true,
outfile: 'output.js'
});


另外提一句,浏览器环境下 import.meta.url 返回的是完整 URL,用 new URL('.', import.meta.url).pathname 在浏览器里其实没啥意义,那是 Node.js 的玩法。
点赞 1
2026-03-02 08:02
端木露露
esbuild 是支持 import.meta.url 的,但问题出在它默认会把 import.meta 当成 Node.js 的特性处理,尤其在你没指定 --target 或平台的时候,它可能会做兼容性转换,把 import.meta 替换成空对象或者直接删掉。

你这种情况,最稳妥的解法是明确告诉 esbuild:「这是浏览器环境,别乱改」,命令行加 --platform=browser --target=esnext,或者用配置文件:

require('esbuild').build({
entryPoints: ['src/index.js'],
bundle: true,
platform: 'browser',
target: 'esnext',
format: 'esm',
outdir: 'dist',
}).catch(() => process.exit(1))


注意 format: 'esm' 也得显式指定,否则 esbuild 可能会按 CommonJS 处理,一处理 import.meta 就凉了。

如果你用的是 esbuild.build() API,别漏了 format;要是用命令行,就写成:

esbuild src/index.js --bundle --platform=browser --target=esnext --format=esm --outfile=dist/bundle.js

另外,别指望 __dirname 在浏览器里天然存在——浏览器压根没有文件系统概念,import.meta.url 是唯一标准 way,但你得保证 esbuild 不把它搞坏。

我之前也踩过这坑,打包完一跑发现 import.meta 是空对象,调试半小时才发现是 esbuild 把它「优化」掉了,加了 target: esnext 就好了,缓存起来别忘了。
点赞
2026-02-25 11:15