提取公共程式碼
提取公共程式碼要藉助 webpack 的 CommonsChunkPlugin 外掛(v4 已移除),另外這個外掛是不支援單入口的公共程式碼塊提取的。
npm init
npm install webpack@^3.0.0 lodash
touch webpack.config.js
mkdir src
touch src/pageA.js
touch src/pageB.js
touch src/subPageA.js
touch src/subPageB.js
touch src/subPageModule.js
複製程式碼
pageA.js:
import './subPageA'
import './subPageB'
import * as _ from 'lodash'
export default 'pageA'
複製程式碼
pageB.js:
import './subPageA'
import './subPageB'
import * as _ from 'lodash'
export default 'pageB'
複製程式碼
subPageA.js
import './subPageModule'
export default 'subPageA'
複製程式碼
subPageB.js
import './subPageModule'
export default 'subPageB'
複製程式碼
subPageModule.js
export default 'subPageModule'
複製程式碼
程式碼引入關係如下:
pageA(pageB)-> lodash,subPageA,subPageB -> subPageModule
如果我們使用平常的多入口打包,即:
webpack.config.js:
var webpack = require('webpack')
var path = require('path')
module.exports = {
entry: {
'pageA': './src/pageA',
'pageB': './src/pageB'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist')
}
}
複製程式碼
打包出來的兩個檔案是十分大的,並且這兩個檔案中存在大量的重複的引入程式碼:
改而使用外掛:
webpack.config.js:
var webpack = require('webpack')
var path = require('path')
module.exports = {
entry: {
'pageA': './src/pageA',
'pageB': './src/pageB',
// 需要提取出來的第三方庫需要在下面設定
'vendor': ['lodash']
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist')
},
plugins: [
/*
* 下面三個外掛的順序在配置中發現只能按照這樣的順序打包才正確打包
*/
// 提取pageA,pageB的公共程式碼
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2,
chunks: ['pageA', 'pageB'] // 解決打包報錯
}),
// 提取第三方庫的程式碼,與上面的vendor對應
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity
}),
// 提取webpack的生成程式碼
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
})
]
}
複製程式碼
在打包結果中,lodash 被提取到了 vendor.bundle.js,subPageA、subPageB、subPageModule 被提取到了 common.bundle.js 中。總體程式碼的體積也縮減了許多(lodash 包太大)
程式碼分割
上面說到 CommonsChunkPlugin 提取公共程式碼是不支援單入口檔案的,使用程式碼分割就可以實現單入口的程式碼塊的分離。
webpack的程式碼分割功能起初是要使用 require.ensure 和 require.include,後面被動態 import() 取代。
require.ensure & require.include
require.ensure 會把給定 dependencies 引數對應的檔案拆分到一個單獨的 bundle 中,此 bundle 會被非同步載入。
require.ensure(dependencies: String[], callback: function(require), errorCallback: function(error), chunkName: String)
複製程式碼
require.ensure 依賴於 promise,使用時最好搭配 polyfill 使用。
require.include 則是用來載入 require.ensure 載入的 chunk 中的子模組。載入的位置要位於父 chunk 之前。
例:
npm init
npm install webpack@^3.0.0 lodash
touch webpack.config.js
mkdir src
touch src/pageA.js
touch src/pageB.js
touch src/subPageA.js
touch src/subPageB.js
touch src/subPageModule.js
複製程式碼
pageA.js:
require.include('./subPageModule')
require.ensure([], function () {
var subPageA = require('./subPageA')
}, 'subPageA')
require.ensure([], function () {
var subPageB = require('./subPageB')
}, 'subPageB')
require.ensure([], function () {
var _ = require('lodash')
}, 'vendor')
export default 'pageA'
複製程式碼
subPageA.js
import './subPageModule'
console.log('subPageA')
export default 'subPageA'
複製程式碼
subPageB.js
import './subPageModule'
console.log('subPageB')
export default 'subPageB'
複製程式碼
subPageModule.js
export default 'subPageModule'
複製程式碼
webpack.config.js
var webpack = require('webpack')
var path = require('path')
module.exports = {
entry: {
'pageA': './src/pageA'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist'),
publicPath: './dist/',
chunkFilename: '[name].bundle.js' // name 為 ensure 引數中的 chunkname
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
})
]
}
複製程式碼
打包結果如下:
動態 import()
import() 引入模組後返回一個 promise,並且使用 magic comments 來配置選項。
npm init
npm install webpack@^3.0.0 lodash
touch webpack.config.js
mkdir src
touch src/pageA.js
touch src/pageB.js
touch src/subPageA.js
touch src/subPageB.js
touch src/subPageModule.js
複製程式碼
pageA.js:
import * as _ from 'lodash'
import(/* webpackChunkName: 'subPageA' */'./subPageA').then(function (subPageA) {
console.log(subPageA)
})
// 使用 magic comments 配置 chunkName
import(/* webpackChunkName: 'subPageB' */'./subPageB').then(function (subPageB) {
console.log(subPageB)
})
export default 'pageA'
複製程式碼
pageB.js:
import * as _ from 'lodash'
import(/* webpackChunkName: 'subPageA' */'./subPageA').then(function (subPageA) {
console.log(subPageA)
})
import(/* webpackChunkName: 'subPageB' */'./subPageB').then(function (subPageB) {
console.log(subPageB)
})
export default 'pageB'
複製程式碼
subPageA.js
import './subPageModule'
console.log('subPageA')
export default 'subPageA'
複製程式碼
subPageB.js
import './subPageModule'
console.log('subPageB')
export default 'subPageB'
複製程式碼
subPageModule.js
export default 'subPageModule'
複製程式碼
webpack.config.js
var webpack = require('webpack')
var path = require('path')
module.exports = {
entry: {
'pageA': './src/pageA',
'pageB': './src/pageB',
'vendor': ['lodash']
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist'),
publicPath: './dist/',
chunkFilename: '[name].bundle.js'
},
plugins: [
// 提取分割出來的程式碼塊中的公共程式碼,這裡是提取到 subPageModule
new webpack.optimize.CommonsChunkPlugin({
names: ['pageA', 'pageB'], // 提取的 entry
async: 'common', // 非同步設為 true 並且設定提取出的字首
minChunks: 2,
children: true // 允許查詢子模組
}),
// 提取第三方包和生成的程式碼
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest'],
minChunks: Infinity
})
]
}
複製程式碼
打包結果如下: