一、按需載入
1.1、為什麼需要按需載入
隨著web應用功能越來越複雜,模組打包後體積越來越大,這樣會帶來兩個問題:
- 所有的js檔案打包到一個bundle.js中導致首屏載入時間過長
- 有時我們只是修改了一個模組就得重新打包所用的檔案 webpack天然支援多種模組系統風格,支援靈活的程式碼分割
1.2、按需載入的三種方式
webpack支援三種程式碼分割方式分別是:
- AMD: require(url, '別名')
- CommonJS: require.ensure([],func),
- ES6: import(url)
1.3、vue中如何按需載入
對應的vue中也有三種對應的解決方式:
- vue非同步元件技術
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/vue-async',
name: 'vueAsync',
component: resolve => require(['@/components/VueAsync'], resolve)
}
]
})
複製程式碼
- webpack提供的require.ensure()
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/require-ensure'
name: 'RequireEnsure',
component: r => require.ensure([], () => r(require('@/components/RequireEnsure'), 'ensure'))
}
]
})
複製程式碼
- 利用ES6提案的import()函式
import Vue from 'vue'
import Router from 'vue-router'
const EsImport = () => import('@/components/EsImport')
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/es-import',
name: 'EsImport',
component: EsImport
}
]
})
複製程式碼
第三種方式比較簡單,而且程式碼組織也比較明顯,所以也更常被使用
二、合理使用commonsChunkPlugin
2.1、為什麼使用commonsChunkPlugin
CommonsChunkPlugin 外掛,是一個可選的用於建立一個獨立檔案(又稱作 chunk)的功能,這個檔案包括多個入口 chunk 的公共模組。簡單來說CommonsChunkPlugin主要是用來提取第三方庫和公共模組,避免首屏載入的bundle檔案或者按需載入的bundle檔案體積過大,從而導致載入時間過長,著實是優化的一把利器。
2.2、commonsPlugin的集中使用場景
- 提取兩個及兩個以上 Chunk 的公共程式碼
- 將 Code Split 切割出來的 Chunk「就是子 Chunk」,提取到父 Chunk
- 將 Code Split 切割出來的 Chunk,提取到一個新的非同步載入的 Chunk
- 提取某個類似 jquery 或 react 的程式碼庫「但是這個用得很少,使用用 dll 外掛來打包會更好一些,一下篇介紹」
三、使用DllPlugin和DllReferencePlugin來提高打包速度
3.1、為什麼使用DllPlugin和DllReferencePlugin
使用 CommonsChunkPlugin,設定 minChunks 為 Infinity 可用於打包此類程式碼,但缺點也是比較明顯的:
- 每次執行 webpack 時,都會去解析打包這些程式碼,耗時也耗資源
- 如果設定了檔名 hash,一次構建生成一個新的hash,那這些檔案即使沒有變,檔名也會變,不利於快取。 對於這些程式碼我是用 Dll 外掛單獨構建。
3.2、vue-cli中如何利用DllPlugin和DllReferencePlugin
- 在build目錄下編寫webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
const AssetsPlugin = require('assets-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
entry: {
libs: [
'vue/dist/vue.esm.js',
'vue-router',
'vuex',
'element-ui'
]
},
output: {
path: path.resolve(__dirname, '../static'),
filename: '[name].[chunkhash:7].js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, '../static/[name]-manifest.json'),
name: '[name]_library',
context: __dirname
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new AssetsPlugin({
filename: 'bundle-config.json',
path: './static'
}),
new CleanWebpackPlugin(['static'], {
root: path.join(__dirname, '../'),
verbose: true,
dry: false
})
]
}
複製程式碼
- 在build目錄下編寫buildDll.js
const path = require('path')
const webpack = require('webpack')
const webpackDll = require('./webpack.dll.conf')
const chalk = require('chalk')
const ora = require('ora')
const rm = require('rimraf')
const spinner = ora({
color: 'green',
text: 'Dll生產中'
})
spinner.start()
rm(path.resolve(__dirname, '../static'), err => {
if(err) throw err
webpack(webpackDll, (err, status) => {
spinner.stop()
if(err) throw err
process.stdout.write(status.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
})
console.log(chalk.cyan('dll success'))
})
複製程式碼
- 修改webpack.base.conf.js
// 新增plugins
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('../static/libs-manifest.json')
})
]
複製程式碼
- 修改webpack.dev.conf.js
const bundleConfig = require("../static/bundle-config.json")//調入生成的的路徑json
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
libJsName: bundleConfig.libs.js
}),
複製程式碼
- 修改webpack.prod.conf.js
const bundleConfig = require("../static/bundle-config.json")//調入生成的的路徑json
new HtmlWebpackPlugin({
...省略號...
libJsName: bundleConfig.libs.js
...省略號...
})
複製程式碼
- 修改index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vue-multipage</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="./static/<%= htmlWebpackPlugin.options.libJsName %>"></script>
</body>
</html>
複製程式碼
參考文章: