讲讲代码分割
webpack可以完成两类代码分割:分离资源,实现缓存资源和并行加载资源
/按需分离
分离资源
- 分离第三方库(vendor)
将一些第三方库保留到与应用程序代码相独立的bundle
上,就可以使用浏览器的缓存 - 分离css
使用ExtractTextWebpackPlugin
来分离css,增强了样式的可缓存性,以及能并行加载样式文件,避免了页面的闪烁问题
按需分离
使用require.ensure([<fileurl>])
代码拆分 – CSS
一般情况下,我们会在webpack.config.js
中做如下配置1
2
3
4
5
6
7
8
9
10module.exports = {
module:{
rules:[
{
test:/.css$/,
use:'css.loader'
}
]
}
}
然而上述的配置不能利用浏览器的异步和并行加载css的能力,这时候网页必须等待,直到整个javascript
包加载完
怎么办呢?
使用ExtractTextWebpackPlugin
,使用前必须先下载这个包1
npm i --save-dev extract-text-webpack-plugin
这时webpack.config.js
作如下改变1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17let ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
module.exports = {
module:{
rules:[
{
test:/.css$/,
use:ExtractTextWebpackPlugin.extract({
use:'css-loader'
})
}
]
},
plugins:[
new ExtractTextWebpackPlugin('styles.css')
]
}
这样之后就能为所有的css模块产生新的bundle,并单独插入到index.html中
官方文档
extract-text-webpack-plugin问题
代码拆分 –库(Libraries)
利用浏览器的缓存就可以使第三方库缓存而不必多次请求,所以将应用代码
和第三方代码
分离很有必要
假设我们使用了第三方的一个库–jquery.js,我们做如下配置1
2
3
4
5
6
7module.exports = {
entry:'./src/index.js',
output:{
filename:'[chunkhash].[name].js',
path:path.resolve(__dirname,'dist')
}
}
这样子,jquery就会被打包到bundle.js
里面了,如果我们改动应用代码,这时候就会重新构建这个文件,浏览器就要重新加载惹。
多入口
我们为jquery添加一个单独的入口,vendor
来缓解1
2
3
4
5
6
7
8
9
10
11var path = require('path');
module.exports = {
enrty:{
main:'./src/index.js',
vendor:'jquery'
},
output:{
filename:'[chunkhash].[name].js',
path:path.resolve(__dirname,'dist')
}
}
这样就有了两个bundle,但是两个文件中都会有jquery
what!!!!
CommonsChunkPlugin出场惹
它从根本上允许我们从不同的bundle中提取所有的公共模块,并将它们加入公共bundle中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var webpack = require('webpack'),
path = require('path');
module.exports = {
entry:{
main:'./src/index.js',
vendor:'jquery'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name:'vendor' //提取公共bundle的name
})
]
}
隐式公共vendor chunk
将CommonsChunkPlugin配置为只接受vendor库1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// 该配置假定你引入的 vendor 存在于 node_modules 目录中
return module.context && module.context.indexOf('node_modules') !== -1;
}
})
]
};
Manifest文件
即使做了如上配置后,我们运行webpack的时候,vendor文件的hash也变了,即使我们分开了两者,所以我们还是没有好好利用浏览器的缓存
这是因为每次构建时候产生的webpack runtime
代码被提取到了公共模块中了,为了解决这个问题,将运行时候的代码提取到单独的manifest
文件中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var webpack = require('webpack');
var path = require('path');
module.exports = {
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 的名字。
})
]
}
代码拆分 –require.ensure
语法:1
require.ensure(dependencies:String[],callback:fn(require),chunkName:String)
坑点
1) 空数组为参数
以下代码保证了拆分点被创建,而且 a.js 被 webpack 分开打包。1
2
3require.ensure([],require=>{
require('./a.js')
})
2) 依赖作为参数1
2
3require.ensure(['./a.js'], function(require) {
require('./b.js');
});
a.js
和 b.js
都被打包到一起,而且从主文件束中拆分出来。但只有 b.js
的内容被执行。a.js
的内容仅仅是可被使用,但并没有被输出。
想去执行 a.js
,我们需要异步
地引用它,如 require('./a.js')
,让它的 JavaScritp 被执行。