定制化Webpack代码分割策略
- 依赖共享
- 使用DllPlugin和DllReferencePlugin:将子应用共享的依赖提前打包成dll文件。例如,多个子应用都依赖
react
和react - dom
,可以通过配置webpack.dll.js
将这两个库打包成一个dll文件。在子应用的webpack.config.js
中使用DllReferencePlugin
引用这个dll文件,这样就避免了每个子应用重复打包相同的依赖。
- External配置:对于一些不会变化且可通过CDN引入的库,如
lodash
,可以在Webpack的externals
配置项中指定。这样在打包子应用时,Webpack不会将这些库打包进子应用的bundle中,而是在运行时从CDN加载,实现依赖共享。例如:
module.exports = {
//...
externals: {
'lodash': '_'
}
};
- 资源加载顺序
- 使用splitChunks配置:
splitChunks
可以控制如何分割代码块。通过cacheGroups
可以定义不同的代码块分组规则。例如,将所有子应用的公共部分提取到一个common
代码块中,并且确保这个common
代码块在其他业务代码块之前加载。
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
common: {
name: 'common',
chunks: 'initial',
minChunks: 2
}
}
}
}
};
- **使用import()动态导入**:在代码中使用`import()`动态导入模块,可以更好地控制资源的加载时机。比如在路由切换时,动态导入相应子应用的代码,确保只有在需要时才加载子应用资源。例如:
const routes = [
{
path: '/sub - app1',
component: () => import('./sub - app1')
}
];
- 代码重复
- 利用splitChunks去重:
splitChunks
的minSize
、minChunks
等配置项可以有效地去除重复代码。例如,当minChunks
设置为2时,表示至少被两个chunk引用的模块才会被提取到公共代码块中,这样可以避免重复打包相同模块。
- 使用别名(Alias):在Webpack的
resolve.alias
配置中,可以为模块设置别名。当不同子应用使用相同模块但路径不同时,通过别名统一路径,避免重复引入模块导致的代码重复。例如:
module.exports = {
//...
resolve: {
alias: {
'@common - utils': path.resolve(__dirname, 'common - utils')
}
}
};
实践中可能遇到的棘手问题及解决方案
- 问题:不同子应用对同一依赖的版本要求不同。
- 解决方案:使用
@module - federation
插件,它可以实现不同版本的依赖在同一个页面上共存。例如,子应用A需要react@16
,子应用B需要react@17
,通过@module - federation
可以配置每个子应用独立加载自己所需版本的react
。
- 问题:动态导入的子应用代码在某些情况下加载失败。
- 解决方案:检查网络请求路径是否正确,确保动态导入的模块路径在部署环境中可访问。同时,可以添加加载错误处理机制,例如在
import()
返回的Promise中使用.catch()
捕获错误,并给出友好的提示信息。
const loadSubApp = () => {
import('./sub - app')
.then(module => {
// 成功加载子应用
})
.catch(error => {
console.error('子应用加载失败', error);
});
};
- 问题:公共代码块过大,影响加载性能。
- 解决方案:进一步优化
splitChunks
的配置,例如根据业务模块对公共代码块进行更细粒度的拆分。也可以考虑对公共代码块进行压缩、Tree - shaking等优化手段,减小其体积。