一、分离第三方库(vendor)
把第三方代码和应用本身的代码一起打包是非常低效的。
因为浏览器会根据缓存头来缓存资源文件,如果文件没有被改变,文件将会被缓存从而不用去再次请求 cdn。
为了利用这一特性,我们希望不管应用本身的代码如何改变,vendor 文件的 hash 始终恒定不变。
用法:
var webpack = require('webpack');
var path = require('path');
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor' // 指定公共 bundle 的名字。
})
]
}
}
为第三方库moment添加一个单独的入口vendor,在不使用CommonsChunkPlugin的情况下,webpack运行后会生成两个bundle,并且两个bundle中都会有moment的代码。
CommonsChunkPlugin允许我们从不同的 bundle 中提取所有的公共模块,并且将他们加入公共 bundle 中。如果公共 bundle 不存在,那么它将会创建一个出来。
利用这个特性,我们指定公共bundle的名字与moment的bundle文件一样,从而让CommonsChunkPlugin提取的公共模块覆盖moment的bundle文件,达到分离第三方库的效果。
至此,我们已经成功的将第三方代码提取到了独立的bundle,但上文提到的浏览器缓存机制我们还是无法用上,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。
解决方案:
var webpack = require('webpack');
var path = require('path');
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest'] // 指定公共 bundle 的名字。
})
]
}
};
最终会生成多一个mainfest bundle
更多介绍见 webpack优化-缓存
二、分离CSS
1、导入 CSS
import 'bootstrap/dist/css/bootstrap.css';
2、使用 css-loader
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: 'css-loader'
}]
}
}
结果,CSS和您的JavaScript打包在一起。
这有个缺点,您将无法利用浏览器的异步和并行加载CSS的能力。这样,您的网页必须等待,直到您的整个JavaScript 包下载完成,然后重绘网页。
3、使用 ExtractTextWebpackPlugin
这个插件要自己安装
module.exports = {
module: {
rules: [{
test: /\.css$/,
- use: 'css-loader'
+ use: ExtractTextPlugin.extract({
+ use: 'css-loader'
+ })
}]
},
+ plugins: [
+ new ExtractTextPlugin('styles.css'),
+ ]
}
三、按需分离
虽然前面几类资源分离,需要用户预先在配置中指定分离模块,但也可以在应用程序代码中创建动态分离模块。
这可以用于更细粒度的代码块,例如,根据我们的应用程序路由,或根据用户行为预测。这可以使用户按照实际需要加载非必要资源。
四、使用 require.ensure() 分离代码
require.ensure(dependencies: String[], callback: function(require), chunkName: String)
两种情况:
// 空数组作为参数
require.ensure([], function(require){
require('./a.js');
});
a.js会被打包到独立的bundle,例如entry打包输出为bundle.js,a.js会被打包为0.bundle.js
//依赖作为参数
require.ensure(['./a.js'], function(require) {
require('./b.js');
});
上面代码, a.js 和 b.js 都被打包到一起,而且从主文件束中拆分出来。但只有 b.js 的内容被执行。a.js 的内容仅仅是可被使用,但并没有被输出。
想去执行 a.js,我们需要异步地引用它,如 require('./a.js'),让它的 JavaScritp 被执行。
网友评论