为什么Webpack打包后模块内容为空?
我在用Webpack打包项目时,发现某个自定义模块导出的内容在打包后变为空对象。比如这个模块:export const data = { name: 'test' },在入口文件import { data } from './module'时控制台却显示data是空的。
已经检查过文件路径没问题,尝试在模块文件里加console.log(data)发现本地可以正常输出,但打包后的bundle.js里对应模块代码变成了module.exports = {}。排查了Webpack配置里的module.rules,所有js相关loader都正常,连注释都去掉了还是不行。
这是我的loader配置片段:
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: { presets: ['@babel/preset-env'] }
}
}
]
}
你现在的配置里只用了
@babel/preset-env,没开modules: false,Webpack 就以为你模块是 CommonJS,结果在 tree-shaking 阶段把没被引用的导出当成“无副作用代码”给干掉了——虽然你确实引用了,但 Webpack 误判了。解决方案有两个:
第一个,改 Babel 配置,明确告诉它别转模块格式:
这样 Babel 就保留 ES Module 原样,Webpack 才能正确做静态分析,tree-shaking 也才能正常工作。
第二个,如果你就是不想动 Babel,也可以在 Webpack 里关掉 tree-shaking(不推荐,影响体积):
不过正常情况第一个方案就够了,你试试先加
modules: false,基本十有八九就解决了。我之前踩过这坑,调试半天发现是 Babel 把 export 转成Object.defineProperty之后 Webpack 就认不出来了……@babel/preset-env默认会把 ES Module 转换成 CommonJS,而 Webpack 在处理模块时可能会被这种转换搞晕,导致最终打包出来的模块内容变为空对象。解决办法其实很简单,你需要在 Babel 的配置里明确告诉它不要乱动你的 ES Module。修改你的 Babel 配置,加上一个选项
modules: false,像这样:这个配置的意思是让 Babel 不要碰你的模块系统,保持 ES Module 的原样,Webpack 自己会处理好这些模块。加了这个配置后重新打包,应该就能正常导出你的
data对象了。顺便吐槽一下,Babel 和 Webpack 的这种配合问题真的是老生常谈了,但每次遇到还是会让人抓狂。尤其是当你排查了半天发现是某个默认行为在作怪的时候,真的想砸键盘。不过还好,踩过一次坑之后就长记性了。希望你能少走点弯路。