• 2
  • 新人请关照

Webpack如何使用DllPlugin打包公共模块,并且能自动找寻入口模块下的子模块。

技术栈:create-ract-app、webpack

  • dll.conf.js
const path = require('path')
const webpack = require('webpack')
const {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');


// dll文件存放的目录
const dllPath = 'public/vendor'

module.exports = {
  entry: {
    // 需要提取的库文件
    vendor: ['react', 'react-dom', 'react-native-storage', 'react-router-dom', 'antd', 'mobx', 'mobx-react',
      'react-css-modules', 'history', 'lodash', 'babel-polyfill'],
    common: ['mime', 'mime-db', 'stream-http', 'ajv', 'psl', 'elliptic', 'sshpk', 'bluebird', 'pako', 'react-error-overlay']
  },
  output: {
    path: path.join(__dirname, dllPath),
    filename: '[name].dll.js',
    // vendor.dll.js中暴露出的全局变量名
    // 保持与 webpack.DllPlugin 中名称一致
    library: '[name]_[hash]'
  },
  plugins: [
    // 清除之前的dll文件
    new CleanWebpackPlugin(),
    // 设置环境变量
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    }),
    // manifest.json 描述动态链接库包含了哪些内容
    new webpack.DllPlugin({
      path: path.join(__dirname, dllPath, '[name]-manifest.json'),
      // 保持与 output.library 中名称一致
      name: '[name]_[hash]',
      context: process.cwd()
    })

  ],
  // optimization:{
  //   splitChunks: {
  //     cacheGroups: {
  //       vendor: {
  //         name: 'vendor',
  //         chunks: 'initial',
  //         minChunks: 10
  //       }
  //     }
  //   }
  // }
}

image.png

  • config-overrides.js


const addCustomize = () => config => {
    if (process.env.NODE_ENV === 'production') {
        config.devtool = false; //去掉map文件
        config.plugins.push(
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: JSON.stringify('production')
                }
            }),
            new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require('./public/vendor/vendor-manifest.json')
            }),
            new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require('./public/vendor/common-manifest.json')
            }),
            // 将 dll 注入到 生成的 html 模板中
            new AddAssetHtmlPlugin({
                // dll文件位置
                filepath: path.resolve(__dirname, './public/vendor/*.js'),
                // dll 引用路径 一般设置为 CDN
                publicPath: 'http://10.20.26.19/ttt/vendor',
                // dll最终输出的目录
                outputPath: './vendor'
            }),
            // 可以解析项目
            new BundleAnalyzerPlugin({
                analyzerMode: 'static'
            })
        )
    }
    return config;
}



module.exports = override(
    
    addCustomize(),

)

这样打包出来dll文件有两个,一个是vendor.js,另一个是common.js,目前这样的配置能够很好的使用。

1、但我的问题是,我已经写了entry入口一些第三方包,为何打包的时候不能自动找寻入口包下面的一些引用包,需要我在common中一一列举出来,大家看看是否有其他简单的方式?
2、为何单个的dll文件为何如此大,要如何分割?
阅读 223
评论
    1 个回答

    我的思路是通过fs读取目录下有哪些manifest.json,然后循环添加对应个数的DllReferencePlugin

    // vue.config.js
    
    const webpack = require('webpack')
    const path = require('path')
    const fs = require('fs')
    const isProd = process.env.NODE_ENV === 'production'
    const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
    
    function resolve() {
      return path.resolve(__dirname, ...arguments)
    }
    
    module.exports = {
      chainWebpack(config) {
        config.when(
          isProd,
          () => {
            config.plugins.delete('preload').delete('prefetch')
    
            // 我写的demo里,dllplugin生成的若干json及若干js放在了public/js/dll目录下
            fs.readdirSync(resolve('./public/js/dll'))
              .forEach(file => {
                // 只关心manifest.json的文件
                if (!file.endsWith('manifest.json')) {
                  return
                }
                // 每有一个manifest.json,就向plugins里增加一个DllReferencePlugin
                config
                  // 有多个DllReferencePlugin时不能都叫同一个名,因此拼接manifest.json文件全名做键
                  .plugin('dll-reference-' + file)
                  .use(webpack.DllReferencePlugin, [{
                    // 拼接manifest.json文件完整路径,引入json
                    manifest: resolve('./public/js/dll', file)
                  }])
              })
    
            config
              .plugin('add-asset')
                .after('html')
                .use(AddAssetHtmlWebpackPlugin)
                  .tap(options => {
                    const outputPath = 'js/dll'
                    const publicPath = config.output.get('publicPath') + outputPath
                    options.push(
                      fs.readdirSync('./public/js/dll')
                        .reduce((op, curr) => {
                          // 读取public/js/dll下的所有文件,只处理js文件
                          if (!curr.endsWith('.js')) {
                            return op
                          }
                          op.push({
                            filepath: require.resolve(resolve(__dirname, './public/js/dll', curr)),
                            outputPath, publicPath
                          })
                          return op
                        }, [])
                    )
                    /*
                    最后生成的options结构是:
                    [
                      [
                          [{
                            filepath: 'public/js/dll/element.js',
                            outputPath, publicPath
                          }],
                          [{
                            filepath: 'public/js/dll/lodash.js',
                            outputPath, publicPath
                          }]
                          ,
                          ...........等等等等
                      ]
                    ]
                    */
                    return options
                  })
                  .end()
          }
        )
      }
    }

    打包出来的js体积大的原因可能有两点:

    1. 依赖本身就大;
    2. 构建dll时没有配置生产模式;
    3. 多配置几个entry,entry内每项的数组长度小些,多生成几个js。你需要的js代码量就那么多了,js多点,每个js体积不就小了么。除数越大,值就越小。

    配置生产模式:

    module.exports = {
      mode: 'production',
      plugins: [
        new DefinePlugin({
          'process.env.NODE_ENV': "'production'"
        })
      ]
    }
      撰写回答

      登录后参与交流、获取后续更新提醒

      相似问题
      推荐文章