esbuild 打包后为什么 import.meta.url 变成 undefined 了?
我用 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);
加上
--format=esm就完事了:如果用的是 API 方式调用,配置里加
format: 'esm':另外提一句,浏览器环境下
import.meta.url返回的是完整 URL,用new URL('.', import.meta.url).pathname在浏览器里其实没啥意义,那是 Node.js 的玩法。import.meta.url的,但问题出在它默认会把import.meta当成 Node.js 的特性处理,尤其在你没指定--target或平台的时候,它可能会做兼容性转换,把import.meta替换成空对象或者直接删掉。你这种情况,最稳妥的解法是明确告诉 esbuild:「这是浏览器环境,别乱改」,命令行加
--platform=browser --target=esnext,或者用配置文件:注意
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就好了,缓存起来别忘了。