qiankun框架使用DllPlugin

81 阅读2分钟

用的版本"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' }]), 
                ], 
}

并且基座中要进行全部引用,子项目中可以选择性的引用,这样就完成了配置