新学webpack2

讲讲代码分割
webpack可以完成两类代码分割:分离资源,实现缓存资源和并行加载资源/按需分离

分离资源

  1. 分离第三方库(vendor)
    将一些第三方库保留到与应用程序代码相独立的bundle上,就可以使用浏览器的缓存
  2. 分离css
    使用ExtractTextWebpackPlugin来分离css,增强了样式的可缓存性,以及能并行加载样式文件,避免了页面的闪烁问题

按需分离

使用require.ensure([<fileurl>])

代码拆分 – CSS

一般情况下,我们会在webpack.config.js中做如下配置

1
2
3
4
5
6
7
8
9
10
module.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
17
let 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
7
module.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
11
var 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
18
var 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
21
var 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
18
var 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
3
require.ensure([],require=>{
require('./a.js')
})

2) 依赖作为参数

1
2
3
require.ensure(['./a.js'], function(require) {
require('./b.js');
});

a.jsb.js 都被打包到一起,而且从主文件束中拆分出来。但只有 b.js 的内容被执行。a.js 的内容仅仅是可被使用,但并没有被输出。

想去执行 a.js,我们需要异步地引用它,如 require('./a.js'),让它的 JavaScritp 被执行。

文章目录
  1. 1. 分离资源
  2. 2. 按需分离
  3. 3. 代码拆分 – CSS
  4. 4. 代码拆分 –库(Libraries)
  • CommonsChunkPlugin出场惹
  • 隐式公共vendor chunk
  • Manifest文件
    1. 1. 代码拆分 –require.ensure
  • 坑点