用的版本"webpack-cli":"^4.9.2"
dll运行命令
"build:dll": "webpack --config webpack.dll.conf.js",
正文:
关于这个dll打包的问题,也是参考了一些文章,但是根据网上文章配置一直也不成功,所以我就自己研究了一下,最后成功了,整体打包时间从40多分钟缩减到了17分钟,也算是一个突破吧,主要项目结构比较复杂,目前没有办法再进行深度优化了。
我将公共依赖都写在根目录package.json的dependencies中,子项目对应的都删除了,然后配置对应的打包命令,删除所有依赖重新下载。
这个webpack.dll.conf.js 放到项目最外层,这个也是从其他人的文章里copy的,这个里边的context 属性是个大坑,一定要记住,因为这个是在根目录,所以编译依赖的时候可以直接使用__dirname
// webpack.dll.conf.js
// 引入依赖
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清空文件用的
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // 压缩代码用的
// 具体配置
module.exports = {
mode: 'production', // 告诉 webpack 当前环境为生产环境
// 入口 dll 自定义模块名字: [依赖1,依赖2,...]
// alias:{
// 'vue$':'vue/dist/vue.esm.js',
// },
entry: {
vue: ['vue', 'vue-router', 'vuex','vue-template-compiler'], // 打包 vue、vue-router、vuex依赖打包到一个叫 vue 的dll模块中去
elementui: ['element-ui'],
three: ['three'],
vendor:['lodash','js-cookie','exceljs','file-saver','dayjs','core-js','mapbox-gl'],
},
// 出口
output: {
filename: 'dll.[name].js', // 其中[name]就是entry中的dll模块名字,因此filename就是dll.vue.js
path: path.resolve(__dirname, './packages/dll/js'), // 输出打包的依赖文件到dll/js文件夹中
library: '[name]_library', // 暴露出的全局变量名,用于给 manifest 映射
},
plugins: [
// 重新打包时,清除之前打包的dll文件
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, './packages/dll/**/*')], // ** 代表文件夹, * 代表文件
}),
// 生成 manifest.json 描述动态链接库包含了哪些内容
new webpack.DllPlugin({
// 暴露出的dll的函数名;此处需要和 output.library 的值一致
// 输出的manifest.json中的name值
name: '[name]_library',
context: __dirname, // 在项目主要的配置中需要和这保持一致
// path 指定manifest.json文件的输出路径
path: path.join(__dirname, `./packages/dll/[name]-manifest.json`), // DllReferencePlugin使用该json文件来做映射依赖。(这个文件会告诉我们的哪些文件已经提取打包好了)
// entryOnly: false // 此乃神坑
}),
new BundleAnalyzerPlugin(), // 压缩
],
};
子项目我们使用的是vue2,在vue.config.js中是这么使用的
configureWebpack: {
plugins: [
new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '../../'),
manifest: require(path.resolve(__dirname, `../dll/vue-manifest.json`)),
})
]
}
子项目配置在packages->xxxx->vue.config.js中,目标node_modules在根目录下,所以子项目的context路径要加../../,才能链接到根目录的node_modules,如果匹配不到,就会导致每次打包都不会将webpack.dll.conf.js中entry里配置的依赖排除在外,因为我项目里配置了好几个entry,所以在子项目里我是这么写的
const dllModule = ['vue','elementui','three','vendor'];
const jsCDN = dllModule.map((i) => `/app/sub-resource/dll/js/dll.${i}.js`); let dllPlugns=[]
if(isProduction){
dllPlugns=dllModule.map(item=>new webpack.DllReferencePlugin({
context: path.resolve(__dirname, '../../'),
manifest: require(path.resolve(__dirname, `../dll/${item}-manifest.json`)),
})) };
configureWebpack: {
plugins: [
...dllPlugns,
new copyWebpackPlugin([{ from: '../dll', to: './dll' }]),
],
}
这样只在生产环境使用,开发环境不受影响,因为打包需要把dll引入进index.html中,我没有使用add的方式添加,我是使用的
config.plugin('html').tap((args) => {
args[0].jsCDN = jsCDN;
return args;
});
在html中这么使用
<!-- 引入JS -->
<% if (process.env.NODE_ENV === 'production') { %>
<% for(var js of htmlWebpackPlugin.options.jsCDN) { %>
<script src="<%=js%>"></script>
<% } %>
<% } %>
虽然有些笨拙,但是挺好用的。
子项目之间不能引用共同的dll,基座也是,所有独立项目都要单独引用,所以每个打包目录下都要copy一份dll的压缩文件
const copyWebpackPlugin = require('copy-webpack-plugin'); configureWebpack: {
plugins: [
new copyWebpackPlugin([{ from: '../dll', to: './dll' }]),
],
}
并且基座中要进行全部引用,子项目中可以选择性的引用,这样就完成了配置