webpack-DllPlugin优化打包性能(基于vue-cli)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_36422236/article/details/84987982

1.介绍

Dll这个概念应该是借鉴了Windows系统的dll。一个dll包,就是一个纯纯的依赖库,它本身不能运行,是用来给你的app引用的。

打包dll的时候,Webpack会将所有包含的库做一个索引,写在一个manifest文件中,而引用dll的代码(dll user)在打包的时候,只需要读取这个manifest文件,就可以了。

简单说

将静态资源文件(运行依赖包)与源文件分开打包,先使用DllPlugin给静态资源打包,再使用DllReferencePlugin让源文件引用资源文件。

2.预打包依赖模块

在根目录创建一个webpack.dll.config.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文件执行webpack打包
webpack --config ./webpack.dll.config.js

还可以把这句加到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"
  },

打包完成后,会在static文件下面有个js文件,其内有个vendor.dll.js,除此之外根目录下还生成了vendor-manifest.json.现在我们已经不再需要将使用的那些包同源文件一起打包了,但是这也需要在源文件的webpack中配置DllReferencePlugin使用vendor-manifest.json来引用这个dll。

3.打包源文件

这一步我们只需要改写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库。

<!DOCTYPE html>
<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>

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

其实还有一个问题

在webpack.config.js中:

  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },

这就代表main.js中的import Vue from ‘vue’ 其实是引用的’vue/dist/vue.esm.js’,而webpack.dll.config.js并不知道vue指代的是’vue/dist/vue.esm.js’,所以我们需要修改webpack.dll.config.js配置:

  vendor: ['vue', 'lodash', 'vuex', 'axios', 'vue-router', 'element-ui']
  },
  entry: {
    vendor: ['vue/dist/vue.esm.js', 'lodash', 'vuex', 'axios', 'vue-router', 'element-ui']
  },

由于我们修改了webpack.dll.config.js,所以我们需要重新打包:

## 重新打包dll
npm run dll
## 重新打包源文件
npm run build

到这里优化就结束了,但是有个小麻烦,我们每次上线的时候需要新建文件夹,然后把index.html复制粘贴进去,再把dist目录粘贴进去,还要把static粘贴进去再上线,我们不希望那么麻烦。

4.提取整个文件夹

首先安装几个插件:

npm install html-webpack-plugin copy-webpack-plugin clean-webpack-plugin --save-dev

然后我们修改webpack.config.js配置:

var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/',
    filename: 'build.[hash].js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true,
    contentBase: path.join(__dirname, 'dist')
  },
  performance: {
    hints: false
  },
  devtool: '#eval-source-map',
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./vendor-manifest.json')
    }),
    new HtmlWebpackPlugin({
      inject: true,
      template: './index.html',
      filename: 'index.html'
    }),
    new CopyWebpackPlugin([
      { from: 'static', to: 'static' }
    ]),
    new CleanWebpackPlugin(['dist'])
  ]
}

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
    })
  ])
}
差别一:
 output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/',
    filename: 'build.[hash].js'
  },
  • 加了hash值,清除浏览器缓存
  • publicPath: ‘/’: 由于index.html需要打包到dist目录下,故’build.[hash].js’的引用路径由/dist/变为/
差别二:

主要是在plugins新添加了三个插件(千万不能加在if里,否则开发环境会出错):

new HtmlWebpackPlugin({
  inject: true,
  template: './index.html'
}),
new CopyWebpackPlugin([
  {from: 'static', to:'static'}
]),
new CleanWebpackPlugin(['dist'])
  • html-webpack-plugin:我们要index.html生成在dist目录里,故引用html-webpack-plugin,它默认将生成的index.html打包在output的文件夹下,由于index.html需要引用打包好的静态dll,且vue需要挂载在根组件div#app上,故需要引入模版,模版为根目录下index.html:
<!DOCTYPE html>
<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>
  </body>
</html>
  • inject:true:将打包好的js文件注入在该html的body底部,保证了script的加载顺序。

  • copy-webpack-plugin:由于我们要引入static/js/中的dll,且是在dist文件下,故用该插件将打包好的静态文件夹拷贝到打包目录dist下。

  • clean-webpack-plugin:打包前清除dist目录

差别三:
  devServer: {
    historyApiFallback: true,
    noInfo: true,
    contentBase: path.join(__dirname, 'dist')
  },

contentBase: path.join(__dirname, ‘dist’),这是为了在dev环境下,提供index.html的目录改为dist,与生产环境的访问文件路径保持一致。

最后

npm run dev就可以愉快的开发啦,npm run build就可以以极速打包好dist目录且上线啦。!!!

猜你喜欢

转载自blog.csdn.net/sinat_36422236/article/details/84987982