在引入第三方的库之后使用webpack打包时,默认会将这些第三方的库重新打包,但是实际上需要重新打包的只有业务代码,这些第三方库是完全不用重新打包的,所以需要对这个过程进行优化。
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
的缺陷:
import
了react)也会导致这个库被重新打包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值也没有变化,但是每次打包过程中都需要生成一遍,无意义减慢了打包的速度。
采用了动态链接库(dll)的思想,这在windows系统下面是一种很常见的思想。一个dll包,就是一个很纯净的依赖库,它本身不能运行,是用来给你的 app 或者业务代码引用的。
webpack提供了这个功能:webpack.DllPlugin。
使用这个功能需要把打包过程分成两步:
首先来打包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>