十六、加載構(gòu)建優(yōu)化
- 懶加載
// 按需加載
oBtn.addEventListener('click', () => {
import('./utils').then(({ default: element }) => {
console.log(element)
document.body.appendChild(element)
})
})
- 預(yù)獲取 & 預(yù)讀取
// 按需加載
oBtn.addEventListener('click', () => {
import(
/* webpackChunkName:'utils' */
/* webpackPreload:true */
'./utils').then(({ default: element }) => {
console.log(element)
document.body.appendChild(element)
})
})
// /* webpackPrefetch:true */
與 prefetch 指令相比,preload 指令有許多不同之處:
preload chunk 會在父 chunk 加載時,以并行方式開始加載。prefetch chunk 會在父 chunk 加載結(jié)束后開始加載。
preload chunk 具有中等優(yōu)先級,并立即下載。prefetch chunk 在瀏覽器閑置時下載。
preload chunk 會在父 chunk 中立即請求,用于當(dāng)下時刻。prefetch chunk 會用于未來的某個時刻。
瀏覽器支持程度不同。
preload 可以使用在首頁很可能需要點擊的按鈕上面
- CDN優(yōu)化
優(yōu)化打包速度, 使用CDN加載提高性能.
// index.html
<!-- cdn可以在對應(yīng)官網(wǎng)查找 -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
// webpack.common.js
output: {
// publicPath: '配置自己的CDN地址'
},
// 排除lodash,加快打包速度
// 使用CDN加載lodash提高性能
// '_'是固定寫法
externals: {
lodash: '_'
}
- dll庫
把大的, 不經(jīng)常變的打包成一個dll庫, 然后使用方直接加載使用。
const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
mode: "production",
// 需要打包的東西
entry: {
react: ['react', 'react-dom']
},
output: {
// 輸出路徑
path: path.resolve(__dirname, 'dll'),
filename: 'dll_[name].js',
// 暴露從入口導(dǎo)出的內(nèi)容, 給使用地方的命名
library: 'dll_[name]'
},
optimization: {
minimizer: [
new TerserPlugin({
// 使用Terser壓縮
// minimize: true,
// 去除注釋文件
extractComments: false
}),
],
},
plugins: [
// 生成dll的插件
new webpack.DllPlugin({
name: 'dll_[name]',
// manifest負責(zé)映射到具體文件
path: path.resolve(__dirname, './dll/[name].manifest.json')
})
]
}
- 使用dll庫
注意dll庫只是幫助我們避免打包了, js里面導(dǎo)入文件不變。
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
const commonConfig = {
/*省略*/
plugins: [
new webpack.DllReferencePlugin({
context: resolveApp('./'),
// 相對于context的路徑
manifest: resolveApp('./dll/react.manifest.json')
}),
//
new AddAssetHtmlPlugin({
// 這個插件目前之后在html里面找auto目錄
outputPath: 'auto',
// 拷貝一份到dist, 同時添加html引用, html從auto里面找
filepath: resolveApp('./dll/dll_react.js')
})
]
}
- css抽取和壓縮
css 150KB再考慮分包,因為這樣增加一次加載。
// webpack.prod.js
// 抽取獨立css
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// 壓縮css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
mode: 'production',
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:8].css'
})
]
}
// webpack.common.js
// 抽取獨立css
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
// 代表向前找一個loader處理
esModule: false
}
}, 'postcss-loader'
]
}
- 作用域提升
作用域提升只能知道esModule的語法
// webpack.prod.js
const webpack = require('webpack')
module.exports = {
mode: 'production',
plugins: [
/* 省略 */
new webpack.optimize.ModuleConcatenationPlugin()
]
}
- TreeShaking
a. usedExports 標記不需要使用的代碼
optimization: {
// 標記不需要使用的代碼:/* unused harmony export foo2 */
usedExports: true,
// 樹搖, TerserPlugin移除不使用的代碼
minimize: true,
}
b. sideEffects 識別副作用
對于不需要使用的類,有選擇的跳過,去除對應(yīng)副作用
// utils.js
window.utils = '1111'
// index.js
import './utils'
//1. 是可以打印的
console.log(window.utils, '<------')
// package.json 代表代碼都是沒有副作用的, 如果沒有使用就移除
"sideEffects": false
//2. 打印為undefined
console.log(window.utils, '<------')
// package.json 代表代碼都是有副作用的,即使沒有使用也不能移除
//3. 使用副作用
"sideEffects": [
"./src/title.js"
]
正常Css文件,我們是需要使用副作用的 ,可以在package.json里面配置,不過一般在webconfig文件里面配置

image.png
c. PurgeCSSPlugin 針對Css文件進行樹搖
yarn add purgecss-webpack-plugin glob --dev
注意及時代碼注釋,主要注釋里面有對應(yīng)標簽,也算使用。
// webpack.prod.js
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const resolveApp = require('./paths')
const glob = require('glob')
module.exports = {
plugins: [
new PurgeCSSPlugin({
// 查找src里面所有文件
paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
safelist: function () {
return {
// 下面css標簽不會被樹搖
standard: ['body', 'html', 'ef']
}
}
})
]
}
- 壓縮部署,http請求的時候節(jié)省資源
yarn add compression-webpack-plugin --dev
// webpack.prod.js
const CompressionPlugin = require("compression-webpack-plugin")
module.exports = {
plugins: [
new CompressionPlugin({
// 只壓縮css 和 js 文件
test: /\.(css|js)$/,
// 默認0.8 只有壓縮比到0.8才生成壓縮文件
minRatio: 0.8,
// 文件大小, 開始壓縮
threshold: 0,
// 壓縮格式
algorithm: 'gzip'
})
]
}
- inlineChunkHtmlPlugin 可以向Html注入內(nèi)容
有時候比較小的文件,可以直接在html中使用,而不需要引入一次。
yarn add inline-chunk-html-plugin --dev
// webpack.prod.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins: [
// 把runtime文件直接注入到 需要的Html文件中
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])
]
}
- webpack 打包 三方庫
output: {
filename: 'sy_utils.js',
path: path.resolve(__dirname, 'dist'),
/// umd 所有模塊化結(jié)合
libraryTarget: 'umd',
// library使用的名稱
library: 'syUtil',
// 調(diào)用全局變量
globalObject: 'this'
}
- 打包時間和內(nèi)容分析
// 時間分析
// webpack.common.js
// 注意兼容性, 需要mini-css-extract-plugin降級到1.3.6
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()
module.exports = (env) => {
/**/
return smp.wrap(mergeConfig)
}
// 內(nèi)容分析
// webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins: [
/**/
new BundleAnalyzerPlugin()
]