webpack02 优化第三方库的打包性能

在引入第三方的库之后使用webpack打包时,默认会将这些第三方的库重新打包,但是实际上需要重新打包的只有业务代码,这些第三方库是完全不用重新打包的,所以需要对这个过程进行优化。

1 externals

Webpack可以配置externals来将依赖的库指向全局变量,从而不再打包这个库,比如对于React:

import React from 'react';

如果你在Webpack.config.js中配置了externals

module.exports = {
  externals: {
    'react': 'window.React'
  }
  //其它配置忽略...... 
};

等于让Webpack知道,对于react这个模块就不要打包,直接指向window.React就好。不过别忘了加载react.min.js(也就是手动的在index.html中引入react),让全局中有React这个变量。

配置externals的缺陷:

  1. 手动引入react.min.js,感觉还是不是很爽;
  2. 有一些库根本没有提供生产环境的文件
  3. 存在反复依赖的库(比如有的库import了react)也会导致这个库被重新打包

2 CommonsChunkPlugin

CommonsChunkPlugin可以将公共包提取出来,还是拿react举例:

const vue = require('react')
{
  entry: {
   // bundle是我们要打包的项目文件的导出名字, app是入口js文件
   bundle: 'app'// vendor就是我们要打包的第三方库最终生成的文件名,数组里是要打包哪些第三方库, 如果不是在node——modules里面,可以填写库的具体地址
   vendor: ['react']
  },
 output: {
     path: __dirname + '/bulid/',
     // 文件名称
    filename: '[name].js'
 },
  plugins: {
    // 这里实例化webpack.optimize.CommonsChunkPlugin构造函数
    // 打包之后就生成vendor.js文件
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor', 'manifest']
    })
  }
}

然后打包生成的文件引入到html文件里面

<script src="/build/vendor.js"></script>
<script src="/build/bundle.js"></script>

再打包的时候将react打包到了vendor.js当中

但是这样打包出的文件名都是相同的,浏览器会缓存上一次的结果导致无法加载最新数据,所以修改output属性,为打包后的文件添加hash值:

module.exports = {
  ...
  output: {
    filename: '[name].[chunkHash:5].js',
    path: path.resolve(__dirname, 'dist')
  },
  ...
}

我们在输出文件名中增加了[chunkHash:5]变量,表示打包后的文件中加入保留5位的hash值

现在打包出的文件bundle和vendor都增加了hash值,我们并不希望vendor的hash发生变化,因为react并没有变化,所以还要修改CommonsChunkPlugin的配置:

module.exports = {
  ...
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor', 'manifest']
    }),
  ]
  ...
}

这样修改完之后vendor的hash值不会在变化,并且多了一个manifest.js文件,manifest.js为webpack的启动文件代码,它会直接影响到hash值,用mainfest单独抽出来了,这样vendor的hash就不会变了。

CommonsChunkPlugind的缺点:就算vendor每次打包没有发生变化,hash值也没有变化,但是每次打包过程中都需要生成一遍,无意义减慢了打包的速度。

3 DLLPlugin

采用了动态链接库(dll)的思想,这在windows系统下面是一种很常见的思想。一个dll包,就是一个很纯净的依赖库,它本身不能运行,是用来给你的 app 或者业务代码引用的。

webpack提供了这个功能:webpack.DllPlugin

使用这个功能需要把打包过程分成两步:

  1. 打包dll包
  2. 引用dll包,打包业务代码

首先来打包dll包,配置一个这样的webpack.dll.config.js(在简而优里面是在build中的vendorLibs.js)

const webpack = require('webpack');
const vendors = ['react', 'react-dom', 'react-router',
  // ...其它库
];
const path = require('path')

module.exports = {
  entry: {
    "lib": vendors,
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].dll.js',
    library: '[name]_lib',
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, 'dist/[name]-manifest.json'),
      // This must match the output.library option above
      name: '[name]_lib',
    }),
  ],
};

webpack.DllPlugin 的选项中:

  • path是manifest.json文件的输出路径,这个文件会用于后续的业务代码打包;
  • name是dll暴露的对象名,要跟output.library保持一致;

然后配置webpack.config.js:

const webpack = require('webpack');

module.exports = {
  entry: {
    app: './src/index.js',
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].bundle.js',
  },
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./dist/vendors-manifest.json'),
    }),
  ],
};

webpack.DllReferencePlugin的选项中:

  • context用来指导Webpack匹配manifest.json中库的路径;
  • manifest用来引入刚才输出的manifest.json文件。

运行Webpack

$ webpack --config webpack.dll.config.js
$ webpack --config webpack.config.js

html引用方式

<script src="/dist/vendors.dll.js"></script>
<script src="/dist/app.bundle.js"></script>

参考

猜你喜欢

转载自blog.csdn.net/duola8789/article/details/80965881
今日推荐