在單頁面或多頁面應用中,經過代碼分離的方式,可以優化性能。javascript
好比把異步加載的代碼分離成一個單獨的chunk,等到須要調用的時候再按需加載(好比click時),這樣能夠減小首屏的代碼體積,從而提升首屏的加載速度。html
另外,在咱們的項目中,可能會用到不少的第三方庫(好比 lodash 、rxjs 等),而每每這些第三方依賴庫的代碼通常不多變化,所以,很適合把第三方依賴庫單獨分離成一個包,而且包名包含 hash( webpack 能夠輕鬆作到),這樣的好處在於,能夠配合瀏覽器http的緩存機制 (好比 max-age ),實現對相關資源包的長緩存,從而優化性能。java
通常須要代碼分割的場景有:node
經過 html-webpack-plugin 自動生成 index.htmlwebpack
npm install -D html-webpack-plugin
npm install -D webpack // html-webpack-plugin 依賴於 webpack
npm install --save axios lodash
複製代碼
// `--` 表明目錄, `-` 表明文件
--demo09
--src
-app.js
-async-module1.js
-async-module2.js
-module.js
-index.html
-webpack.config.js
複製代碼
src/async-module1.jsios
export const data = 'this is async module1';
複製代碼
src/async-module2.jsgit
export const data = 'this is async module2';
複製代碼
src/module.jsgithub
export const sayHello1 = () => {
console.log('Hi I want to say hello1');
}
export const sayHello2 = () => {
console.log('Hi I want to say hello2');
}
export const sayHello3 = () => {
console.log('Hi I want to say hello3');
}
複製代碼
src/app.jsweb
import { sayHello1, sayHello2, sayHello3 } from './module';
sayHello1();
sayHello2();
sayHello3();
// 異步加載 async-module1
setTimeout(() => {
require.ensure(
[],
function () {
const asyncModule = require("./async-module1");
console.log(asyncModule.data);
},
"module1"
);
}, 3000);
// 異步加載 async-module2
setTimeout(() => {
require.ensure(
[],
function () {
const asyncModule2 = require("./async-module2");
console.log(asyncModule2.data);
},
"module2"
);
}, 3000);
// 引用第三方庫
// https://github.com/lodash/lodash
import * as _ from "lodash";
// https://github.com/axios/axios
import * as axios from "axios";
console.log(_);
console.log(axios);
複製代碼
使用 webpack4 的 splitChunks
能夠很容易的作到。npm
關於splitChunks
的各個參數的用法,能夠看個人這篇文章 demo08 關於SplitChunksPlugin
splitChunks: {
cacheGroups: {
vendors: {
chunks: "all", // 使用 all 模式
test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 下的模塊
name: "vendors", // 包命名,最終的命名要結合 output 的 chunkFilename
minChunks: 1,
minSize: 30000,
priority: 10 // 設置優先級
}
}
}
複製代碼
打包異步加載包
splitChunks: {
cacheGroups: {
async: {
chunks: "async",
minChunks: 1, // 代碼塊至少被引用的次數
maxInitialRequests: 3, // 設置最大的請求數
minSize: 0, // 設置每一個 chunk 最小的大小 (默認30000),這裏設置爲 0,以方便測試
automaticNameDelimiter: '~',
priority: 9
},
}
}
複製代碼
const path = require("path");
module.exports = {
mode: 'development', // 使用development模式,方便看到各個包名中的 [name],以區分各個包,在production模式下,[name]會被轉化爲0 1 2...
entry: {
app: "./src/app.js",
},
output: {
publicPath: __dirname + "/dist/", // 打包後資源文件的引用會基於此路徑
path: path.resolve(__dirname, "dist"), // 打包後的輸出目錄
filename: "[name].[chunkhash].bundle.js", // 每一個包包含 chunkhash
chunkFilename: "[id].[chunkhash].chunk.js"
},
optimization: {
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
async: {
chunks: "async",
minChunks: 1, // 代碼塊至少被引用的次數
maxInitialRequests: 3, // 設置最大的請求數
minSize: 0, // 設置每一個 chunk 最小的大小 (默認30000),這裏設置爲 0,以方便測試
automaticNameDelimiter: '~',
priority: 9
},
vendors: {
chunks: "all", // 使用 all 模式
test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 下的模塊
name: "vendors", // 包命名,最終的命名要結合 output 的 chunkFilename
minChunks: 1,
minSize: 30000,
priority: 10 // 設置優先級
}
}
}
}
};
複製代碼
(默認你已經安裝了全局 webpack 以及 webpack-cli )
webpack
複製代碼
打包成功後,結果輸出在 demo09 的 dist 目錄下
(注意這裏設置 "mode"
爲 "development"
)
app.226a343cb53e0a689358.chunk.js (app主模塊)
async~module1.87d116fd41640c30a6b2.chunk.js (async-module1模塊)
async~module2.65866f4d15253512c981.chunk (async-module2模塊)
runtime.4e6de616bd3030f8bff8.bundle.js (webpack運行時模塊)
vendors.a83c085b3a7ac03b1b47.chunk.js (第三方依賴模塊)
複製代碼
能夠經過修改 app.js 等代碼,再次運行 webpack
命令,你會發現,第三方依賴模塊的包名沒有被改變: vendors.a83c085b3a7ac03b1b47.chunk.js
。
在瀏覽器運行 dist/index.html,打開控制檯能夠觀察異步加載模塊的效果。
(備註:runtime.xxxxxxxx.bundle.js模塊包含了對異步加載模塊的引用邏輯,此外,異步加載引用的相對路徑受
output -> publicPath
配置的影響)
demo 代碼地址: github.com/SimpleCodeC…
倉庫代碼地址(及目錄): github.com/SimpleCodeC…