webpack之dll(拆分bundles)

3,382 阅读4分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

dll的作用

dll的作用是将项目中一些不常改变的依赖单独打包,DllReferencePlugin通过DllPlugin生成的manifest.json文件去引用对应的依赖。

优点

  • 一旦生成dll文件,只要依赖不变,dll文件就不会改变
  • dll中的依赖包只需要在文件生成的时候进行一次编译打包,以后的构建过程就可以跳过这些依赖,加快构建过程

缺点

  • 需要增加一份生成dll文件的webpack配置,并且要修改原来的配置项去引入dll文件
  • 需要多余的一次webpack构建,打破原先的项目构建流程
  • 在dll中的依赖有版本改变的时候,需要重新生成dll文件

总结:

dll的功能就是对代码分割的一种高级应用,将项目中很少变动的依赖先配置出来,提前打包在一个文件中,然后以script标签的方式注入到index.html文件中,接着在build配置中引入打包好的dll配置,这样build执行时会跳过dll中已经打包的模块,从而加快了build的打包时间

实操:

1:首先,我们需要为dll单独写一个配置文件,以vue-cli为例,我们在build中新建一个名为webpack.dll.conf.js文件


var path = require("path");
var webpack = require("webpack");

module.exports = {
  // 你想要打包的模块的数组
  entry: {
    vendor: ['vue', 'lodash', 'vuex', 'axios', 'vue-router', 'element-ui']
  },
  output: {
    path: path.join(__dirname, './static/js'), // 打包后文件输出的位置
    filename: '[name].dll.js',
    library: '[name]_library' 
    // vendor.dll.js中暴露出的全局变量名。
    // 主要是给DllPlugin中的name使用,
    // 故这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '.', '[name]-manifest.json'),
      name: '[name]_library', 
      context: __dirname
    }),
    // 压缩打包的文件,与该文章主线无关
    new webpack.optimize.UglifyJsPlugin({ 
      compress: {
        warnings: false
      }
    })
  ]
};

重点:这里引入的Dllplugin插件,该插件将生成一个manifest.json文件,该文件供webpack.config.js中加入的DllReferencePlugin使用,使我们所编写的源文件能正确地访问到我们所需要的静态资源(运行时依赖包)。

  • path:manifest.json生成的文件夹及名字,该项目让它生成在了根目录下。

  • name:和output. library保持一致即可。

  • context:选填,manifest文件中请求的上下文,默认为该webpack文件上下文。 (!!!我在学习这个插件时一直没有成功的坑点之一!!,这个上下文必须必须同webpack.config.js中DllReferencePlugin插件的context所指向的上下文保持一致!!)
    编写该webpack配置之后,我们就可以预打包资源文件了!!

// package.json文件

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress",
    "dll": "webpack --config ./webpack.dll.config.js"
  },

完成打包后就可以看见生成的vendor.dll.js文件了,除此之外根目录中还生成了vendor-manifest.json

image.png

现在我们已经不再需要将使用的那些包同源文件一起打包了,但是这也需要在源文件的webpack中配置DllReferencePlugin使用vendor-manifest.json来引用这个dll。

step 4:打包源文件

这一步我们只需要改写vue-cli为我们生成好的webpack.config.js即可:

var path = require('path')
var webpack = require('webpack')

module.exports = {
 entry: './src/main.js',
 output: {
   path: path.resolve(__dirname, './dist'),
   publicPath: '/dist/',
   filename: 'build.js'
 },
 module: {
   // ...(省略未复制,并不是删除了module里的东西)
 },
 resolve: {
   alias: {
     'vue$': 'vue/dist/vue.esm.js'
   }
 },
 devServer: {
   historyApiFallback: true,
   noInfo: true
 },
 performance: {
   hints: false
 },
 devtool: '#eval-source-map',
 plugins: [
   new webpack.DllReferencePlugin({
     context: __dirname,
     manifest: require('./vendor-manifest.json')
   })
 ]
}

if (process.env.NODE_ENV === 'production') {
 module.exports.devtool = '#source-map'
 // http://vue-loader.vuejs.org/en/workflow/production.html
 module.exports.plugins = (module.exports.plugins || []).concat([
   new webpack.DefinePlugin({
     'process.env': {
       NODE_ENV: '"production"'
     }
   }),
   new webpack.optimize.UglifyJsPlugin({
     sourceMap: true,
     compress: {
       warnings: false
     }
   }),
   new webpack.LoaderOptionsPlugin({
     minimize: true
   })
 ])
}

该文件里主要是添加了plugins配置:

plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./vendor-manifest.json')
    })
  ]
  • context:与Dllplugin里的context所指向的上下文保持一致,这里都是指向了根目录。
  • manifest:引入Dllplugin所生成的的manifest。

你以为完了? 其实还没有。
我们需要手动在根目录的index.html里引入所生成的dll库

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>dll-test</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="./static/js/vendor.dll.js"></script>
    <script src="/dist/build.js"></script>
  </body>
</html>

这里也很讲究,也是我之前失败的原因之一!!我之前直接把<script src="./static/js/vendor.dll.js"></script>写到了<script src="/dist/build.js"></script>的后面,导致一直报错!其实这里稍微动动脑筋就能明白,我们在main.js中引入的各种包,而main.js最终被打包为了build.js,那么我们肯定要先把包引进来才能正确使用build.js啊!所以vendor.dll.js必须放在build.js之前引入。

激动人心的时刻到来了!!我们只需要npm run dev就可以了!