編譯分析插件
webpack-bundle-analyzer
webpack-bundle-analyzer
可以生成代碼分析報(bào)告,可以直觀地分析打包出的文件有哪些,及它們的大小、占比情況、各文件 Gzipped 后的大小、模塊包含關(guān)系、依賴項(xiàng)等
npm i -D webpackbar webpack-bundle-analyzer
javascript
復(fù)制代碼
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); ? module.exports = { ?// ... ?plugins: [ ? ?new BundleAnalyzerPlugin(), ] } //package.json "scripts": { ? "analyz": "webpack-bundle-analyzer --port 8888 ./build/stats.json", }
新版的 vue-cli 也內(nèi)置了webpack-bundle-analyzer
json
復(fù)制代碼
"scripts": { "analyz": "vue-cli-service build --report", },
配置:
-
analyzerMode:server / static / json / disabled
默認(rèn)值:server。 在server 模式下,分析器將啟動(dòng) HTTP 服務(wù)器以顯示 bundle 報(bào)告。 在 static 模式下,將生成帶有 bundle 報(bào)告的單個(gè) HTML 文件。 在 json 模式下,將生成帶有捆綁報(bào)告的單個(gè) JSON 文件。 在 disable 模式下,您可以使用此插件通過(guò)將 generateStatsFile 設(shè)置為 true 來(lái)生成 Webpack Stats JSON 文件。
-
analyzerHost:默認(rèn)值:127.0.0.1。 在 server 模式下用于啟動(dòng) HTTP 服務(wù)器的主機(jī)。
-
analyzerPort:默認(rèn)值:8888。在 server 模式下用于啟動(dòng) HTTP 服務(wù)器的端口
-
reportFilename:默認(rèn)值:report.html。 在 static 模式下生成的捆綁報(bào)告文件的路徑。 它可以是絕對(duì)路徑,也可以是相對(duì)于 bundle 文件輸出目錄的路徑(在 webpack 配置中是 output.path)。
-
defaultSizes:stat / parsed / gzip
默認(rèn)值:parsed。 默認(rèn)情況下在報(bào)告中顯示的模塊大小。
stat:這是文件的“輸入”大小,在進(jìn)行任何轉(zhuǎn)換(如縮小)之前。之所以稱(chēng)為“stat size”,是因?yàn)樗菑?Webpack 的 stats 對(duì)象中獲取的。
parsed:這是文件的“輸出”大小。 如果你使用的是 Uglify 之類(lèi)的 Webpack 插件,那么這個(gè)值將反映代碼的縮小后的大小。
gzip:這是通過(guò) gzip 壓縮運(yùn)行解析的包/模塊的大小。
-
openAnalyzer:默認(rèn)值:true。 在默認(rèn)瀏覽器中自動(dòng)打開(kāi)報(bào)告。
-
genarateStatsFile:默認(rèn)值:false。 如果為 true,將在 bundle 輸出目錄中生成 webpack stats JSON 文件
webpackbar
webpackbar
提供了友好的編譯進(jìn)度提示
ini
復(fù)制代碼
const WebpackBar = require('webpackbar'); ? module.exports = { // ... plugins: [ ? new WebpackBar(), ] }
speed-measure-webpack-plugin
優(yōu)化 webpack 構(gòu)建速度,首先需要知道是哪些插件、哪些 loader 耗時(shí)長(zhǎng),方便我們針對(duì)性的優(yōu)化。通過(guò) speed-measure-webpack-plugin?插件進(jìn)行構(gòu)建速度分析,可以看到各個(gè) loader、plugin 的構(gòu)建時(shí)長(zhǎng),后續(xù)可針對(duì)耗時(shí) loader、plugin 進(jìn)行優(yōu)化。
css
復(fù)制代碼
npm i -D speed-measure-webpack-plugin
構(gòu)建速度優(yōu)化
緩存
Webpack
Webpack 中幾種緩存方式:
cache-loader
hard-source-webpack-plugin
以上這些緩存方式都有首次啟動(dòng)時(shí)的開(kāi)銷(xiāo),即它們會(huì)讓 “冷啟動(dòng)” 時(shí)間會(huì)更長(zhǎng),但是二次啟動(dòng)能夠節(jié)省很多時(shí)間
babel-loader
babel-loader的options設(shè)置中增加cacheDirectory屬性,屬性值為true。表示:開(kāi)啟babel緩存,第二次構(gòu)建時(shí)會(huì)讀取之前的緩存,構(gòu)建速度會(huì)更快一點(diǎn)。
yaml
復(fù)制代碼
{ test: /.js$/, loader: 'babel-loader', options: { cacheDirectory: true } }
cache-loader
webpack.docschina.org/loaders/cac…
在一些性能開(kāi)銷(xiāo)較大的 loader 之前添加 cache-loader,將結(jié)果緩存中磁盤(pán)中。默認(rèn)保存在 node_modueles/.cache/cache-loader 目錄下。
java
復(fù)制代碼
module.exports = { //... module: { //我的項(xiàng)目中,babel-loader耗時(shí)比較長(zhǎng),所以我給它配置了`cache-loader` rules: [ { test: /.jsx?$/, use: ['cache-loader','babel-loader'] } ] } }
如果你跟我一樣,只打算給 babel-loader 配置 cache 的話,也可以不使用 cache-loader,給 babel-loader 增加選項(xiàng) cacheDirectory。
持久化緩存
通過(guò)配置 webpack 持久化緩存?cache: filesystem
,來(lái)緩存生成的 webpack 模塊和 chunk,改善構(gòu)建速度。
簡(jiǎn)單來(lái)說(shuō),通過(guò) cache: filesystem
可以將構(gòu)建過(guò)程的 webpack 模板進(jìn)行緩存,大幅提升二次構(gòu)建速度、打包速度,當(dāng)構(gòu)建突然中斷,二次進(jìn)行構(gòu)建時(shí),可以直接從緩存中拉取,可提速 90% 左右。
java
復(fù)制代碼
module.exports = { cache: { type: 'filesystem', // 使用文件緩存 }, }
hard-source-webpack-plugin
HardSourceWebpackPlugin 和 speed-measure-webpack-plugin 不能一起使用
vue
cache-loader
Vue-Cli自帶cache-loader ,會(huì)默認(rèn)為 Vue/Babel/TypeScript
編譯開(kāi)啟。文件會(huì)緩存在 node_modules/.cache
中。
cache-loader
進(jìn)行以下兩個(gè)的緩存了
- babel-loader 的 cacheDirectory 標(biāo)志
- vue-loader 的 cacheDirectory 標(biāo)志
hard-source-webpack-plugin
這個(gè)插件能正常使用的版本是
webpack5
以下的版本。
npm install --save-dev hard-source-webpack-plugin
為模塊提供中間緩存,緩存路徑是:node_modules/.cache/hard-source
php
復(fù)制代碼
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin') module.exports = { configureWebpack: config => { config.plugin.push( // 為模塊提供中間緩存,緩存路徑是:node_modules/.cache/hard-source new HardSourceWebpackPlugin({ root: process.cwd(), directories: [], environmentHash: { root: process.cwd(), directories: [], files: ['package.json', 'yarn.lock'] } }) // 配置了files的主要原因是解決配置更新,cache不生效了的問(wèn)題,配置后有包的變化,plugin會(huì)重新構(gòu)建一部分cache ) } }
hash緩存
防止編譯文件名字重復(fù),部署版本的時(shí)候,瀏覽器使用緩存文件。同時(shí),如果編譯時(shí)文件未改動(dòng),不會(huì)改變文件名和文件的
hash、chunkhash、contenthash
hash是一整個(gè)項(xiàng)目,一次打包,只有一個(gè)hash值,是項(xiàng)目級(jí)的
chunhash是從入口entry出發(fā),到它的依賴,以及依賴的依賴,依賴的依賴的依賴,等等,一直下去,所打包構(gòu)成的代碼塊(模塊的集合)叫做一個(gè)chunk,也就是說(shuō),入口文件和它的依賴的模塊構(gòu)成的一個(gè)代碼塊,被稱(chēng)為一個(gè)chunk。
contenthash是哈希只跟內(nèi)容有關(guān)系,內(nèi)容不變,哈希值不變。與chunkhash的區(qū)別可以舉上面contenthash的例子,同時(shí)可以說(shuō)明contenthash跟內(nèi)容有關(guān),但是chunkhash會(huì)考慮很多因素,比如模塊路徑、模塊名稱(chēng)、模塊大小、模塊id等等。
lua
復(fù)制代碼
output: { filename: '[name].[contenthash].js', // contenthash 只有在內(nèi)容發(fā)生改變才會(huì)變 path: path.resolve(__dirname, 'dist'), //輸出路徑 __dirname 代表當(dāng)前文件的絕對(duì)路徑 clean: true, //在生成文件之前清空 output 目錄 }, vue-cli configureWebpack -> config.output.filename = `js/[name].[contenthash].js`; config.output.chunkFilename = `js/[name].[contenthash].js`;
在提取css時(shí)我們也可以這么命名文件名
css
復(fù)制代碼
// css 提取 plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:10].css', }), ]
dll
將我們項(xiàng)目中的依賴使用dll插件進(jìn)行動(dòng)態(tài)鏈接,這樣依賴就不會(huì)進(jìn)行編譯,從而極大地提高編譯速度
webpack5 開(kāi)箱即用的持久緩存是比 dll 更優(yōu)的解決方案
將dll和緩存進(jìn)行對(duì)比可以發(fā)現(xiàn):
緩存 | DLL |
---|---|
把常用的文件存儲(chǔ)到內(nèi)存或硬盤(pán)中 | 把公共代碼打包為dll文件放到硬盤(pán)中 |
再次打包時(shí),直接取讀取緩存 | 再次打包時(shí),讀取dll文件,不重新打包 |
加載時(shí)間減少 | 打包時(shí)間減少 |
autodll-webpack-plugin
多線程
將文件解析任務(wù)分解成多個(gè)子進(jìn)程并發(fā)執(zhí)行,發(fā)揮多核 CPU 電腦的威力。子進(jìn)程處理完任務(wù)后再將結(jié)果發(fā)送給主進(jìn)程。所以可以大大提升 Webpack 的項(xiàng)目構(gòu)建速度
happypack
happypack?同樣是用來(lái)設(shè)置多線程,但是在 webpack5 就不要再使用 happypack?了,官方也已經(jīng)不再維護(hù)了,推薦使用 thread-loader。
npm install happypack -D
HappyPack 參數(shù)
-
id: String
用唯一的標(biāo)識(shí)符 id 來(lái)代表當(dāng)前的 HappyPack 是用來(lái)處理一類(lèi)特定的文件. -
loaders: Array
用法和 webpack Loader 配置中一樣. -
threads: Number
代表開(kāi)啟幾個(gè)子進(jìn)程去處理這一類(lèi)型的文件,默認(rèn)是3個(gè),類(lèi)型必須是整數(shù)。 -
verbose: Boolean
是否允許 HappyPack 輸出日志,默認(rèn)是 true。 -
threadPool: HappyThreadPool
代表共享進(jìn)程池,即多個(gè) HappyPack 實(shí)例都使用同一個(gè)共享進(jìn)程池中的子進(jìn)程去處理任務(wù),以防止資源占用過(guò)多。 -
verboseWhenProfiling: Boolean
開(kāi)啟webpack --profile
,仍然希望HappyPack產(chǎn)生輸出。 -
debug: Boolean
啟用debug 用于故障排查。默認(rèn)false
。
javascript
復(fù)制代碼
//提升 Webpack 構(gòu)建速度 const HappyPack = require('happypack'); //安裝 OS 模塊 這個(gè)主要是拿到當(dāng)前電腦的CPU核數(shù) const os = require('os'); //這個(gè)是設(shè)置共享線程池中的數(shù)量 size 控制設(shè)置數(shù)量 類(lèi)型 只能是 整數(shù)類(lèi)型 const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); ? module.exports = { ?module: { ? ?rules: [ ? ? { ? ? ? ?test: /.js$/, ? ? ? ?//把對(duì).js 的文件處理交給id為happyBabel 的HappyPack 的實(shí)例執(zhí)行 ? ? ? ?loader: 'happypack/loader?id=happyBabel', ? ? ? ?//排除node_modules 目錄下的文件 ? ? ? ?exclude: /node_modules/ ? ? }, ? ? { ? ? ? ? ? ?test: /.(css|less)$/, ? ? ? ? ? ?use: 'happypack/loader?id=styles' ? ? }, ? ] }, plugins: [ ? ?new HappyPack({ ? ? ? //用id來(lái)標(biāo)識(shí) happypack處理那里類(lèi)文件 ? ? ?id: 'happyBabel', ? ? ?//用法和loader 的配置一樣 ? ? ?loaders: [{ ? ? ? ?loader: 'babel-loader?cacheDirectory=true', ? ? }], ? ? ?//共享進(jìn)程池 ? ? ?threadPool: happyThreadPool, ? ? ?//允許 HappyPack 輸出日志 ? ? ?verbose: true, ? }), ? ?new HappyPack({ ? ? ? ?id: 'styles', ? ? ? ?loaders: [ 'style-loader', 'css-loader', 'less-loader' ], ? ? ? ?//共享進(jìn)程池 ? ? ? ?threadPool: happyThreadPool, ? }); ] }
vue
lua
復(fù)制代碼
? //把對(duì).js 的文件處理交給id為happyBabel 的HappyPack 的實(shí)例執(zhí)行 ? // config.module.rule('js').test(/.js$/) ? // ? .include.add('/src/').end() ? // ? .exclude.add('/node_modules/').end() ? // ? .use().loader('happypack/loader?id=happyBabel').end()
thread-loader
-
Webpack
npm install --save-dev thread-loader
javascript復(fù)制代碼
const path = require("path"); module.exports = { module: { ? rules: [ ? ? { ? ? ? test: /.js$/, ? ? ? include: path.resolve('src'), ? ? ? use: [ ? ? ? ? "thread-loader", ? ? ? ? // 耗時(shí)的 loader (例如 babel-loader) ? ? ? ], ? ? }, ? ], }, };
-
Vue-Cli已經(jīng)內(nèi)置
javathread-loader
,thread-loader 會(huì)在多核 CPU 的機(jī)器上為Babel/TypeScript
轉(zhuǎn)譯開(kāi)啟。復(fù)制代碼
module.exports = { parallel: true, }
-
Type:
boolean
-
Default:
require('os').cpus().length > 1
是否為 Babel 或 TypeScript 使用
thread-loader
。該選項(xiàng)在系統(tǒng)的 CPU 有多于一個(gè)內(nèi)核時(shí)自動(dòng)啟用,僅作用于生產(chǎn)構(gòu)建。
-
縮小文件檢索解析范圍
alias
- 為避免無(wú)用的檢索與遞歸遍歷,可以使用alias指定引用時(shí)候的模塊
extensions
-
extensions 表示需要解析的文件類(lèi)型列表。
根據(jù)項(xiàng)目中的文件型,定義 extensions,以覆蓋 webpack 默認(rèn)的 extensions,加快解析速度。
由于 webpack 的解析順序是從左到右,因此要將使用頻率高的文件類(lèi)型放在左側(cè),如下我將
javatsx
放在最左側(cè)復(fù)制代碼
module.exports = { ? resolve: { ? ? ? extensions: ['.tsx', '.js'], // 因?yàn)槲业捻?xiàng)目只有這兩種類(lèi)型的文件,如果有其他類(lèi)型,需要添加進(jìn)去。 ? } }
noParse
- noParse,對(duì)不依賴本地代碼的第三方依賴不進(jìn)行解析,比如CDN引用的第三方依賴。
include
- 為 loader 指定 include,減少 loader 應(yīng)用范圍,僅應(yīng)用于最少數(shù)量的必要模塊,。
import優(yōu)化
運(yùn)用這個(gè)插件能在代碼使用了import語(yǔ)法的情況下,大大提高代碼的編譯速度。
安裝 babel-plugin-dynamic-import-node
kotlin
復(fù)制代碼
npm install --save-dev babel-plugin-dynamic-import-node
vue-cli3
修改babel.config.js文件
css
復(fù)制代碼
module.exports = { presets: ["@vue/cli-plugin-babel/preset"], env: { ? development: { ? ? plugins: ["dynamic-import-node"] ? } } };
vue.cli2
.babelrc文件
json
復(fù)制代碼
"env": { ? ? ? "test": { ? ? ? ? ? ? ? ? "plugins": [] ? ? ? ? ? ? ? }, ? ? ? "development":{ ? ? ? ? ? ? ? ? ? ? ? "presets": ["env", "stage-2"], ? ? ? ? ? ? ? ? ? ? ? "plugins": ["dynamic-import-node"] ? ? ? ? ? ? ? ? ? ? } ? ? ? }
打包體積優(yōu)化
某些 utility, plugin 和 loader 都只用于生產(chǎn)環(huán)境。例如,在開(kāi)發(fā)環(huán)境下使用 TerserPlugin
來(lái) minify(壓縮) 和 mangle(混淆破壞) 代碼是沒(méi)有意義的。通常在開(kāi)發(fā)環(huán)境下,應(yīng)該排除以下這些工具:
TerserPlugin
-
[fullhash]
/[chunkhash]
/[contenthash]
代碼分離
www.cnblogs.com/Mr-Hou88888…
blog.csdn.net/qq_41887214…
代碼分離code splitting是 webpack 中最引人注目的特性之一。此特性能夠把代碼分離到不同的 bundle 中,然后可以按需加載或并行加載這些文件。代碼分離可以用于獲取更小的 bundle,加快打包速度,以及控制資源加載優(yōu)先級(jí),如果使用合理,會(huì)極大影響加載時(shí)間。
多入口起點(diǎn)
入口起點(diǎn)(entry points)
src/index.js
arduino
復(fù)制代碼
console.log('Hello world!');
src/another-module.js
javascript
復(fù)制代碼
import _ from 'lodash' ? console.log(_.join(['another', 'module', 'chunk'], ' '));
這個(gè)模塊依賴了 lodash ,需要安裝一下:
復(fù)制代碼
npm install lodash
webpack.config.js
css
復(fù)制代碼
module.exports = { mode: 'development', entry: { // 配置多入口文件 ? index: './src/index.js', ? another: './src/another_module.js' }, ? output: { ? ? filename: 'bundle.js', ? ? path: path.resolve(__dirname, './dist'), ? }, } ?
執(zhí)行webpack
命令,可以看到報(bào)錯(cuò)了 ̄□ ̄||
css
復(fù)制代碼
module.exports = { mode: 'development', entry: { ? index: './src/index.js', ? another: './src/another_module.js' }, output: { ? filename: '[name].bundle.js', // 對(duì)應(yīng)多個(gè)出口文件名 ? path: path.resolve(__dirname, './dist'), }, }
執(zhí)行webpack
命令,可以看到不報(bào)錯(cuò)了,并且dist
輸出了兩個(gè)js文件
文件another.bundle.js
來(lái)源于entry.another
,即src/another.js
,文件大小為554kb
,因?yàn)楸?code>lodash被打包進(jìn)去了
文件index.bundle.js
來(lái)源于entry.index
,即src/index.js
,文件大小為1.21kb
但是,如果我們的其他入口也需要使用lodash
呢?
javascript
復(fù)制代碼
src/index.js import _ from 'lodash' ? console.log(_.join(['index', 'module', 'chunk'], ' '));
lodash
在兩個(gè)引用文件中都被打包了,我們期望lodash
應(yīng)該是公用的
配置 dependOn option
選項(xiàng),這樣可以在多個(gè) chunk 之間共享模塊
css
復(fù)制代碼
module.exports = { mode: 'development', entry: { ? index: { ? ? import: './src/index.js', // 啟動(dòng)時(shí)需加載的模塊 ? ? dependOn: 'common_chunk', // 當(dāng)前入口所依賴的入口 ? }, ? another: { ? ? import: './src/another_module.js', ? ? dependOn: 'common_chunk', ? }, ? ? common_chunk: 'lodash' // 當(dāng)上面兩個(gè)模塊有l(wèi)odash這個(gè)模塊時(shí),就提取出來(lái)并命名為shared chunk }, output: { ? filename: '[name].bundle.js', // 對(duì)應(yīng)多個(gè)出口文件名 ? path: path.resolve(__dirname, './dist'), }, } ?
執(zhí)行webpack
命令,可以看到打包結(jié)果
已經(jīng)提取出來(lái)common_chunk.bundle.js
,即為提取打包了lodash
公用模塊
index.bundle.js
another.bundle.js
體積也變小
分離 Vendor
chunk-vendors.js :顧名思義,chunk-vendors.js 是捆綁所有不是自己的模塊,而是來(lái)自其他方的模塊的捆綁包,它們稱(chēng)為第三方模塊或供應(yīng)商模塊。
通常,它意味著(僅和)來(lái)自項(xiàng)目 /node_modules 目錄的所有模塊,會(huì)將所有 /node_modules 中的第三方包打包到 chunk-vendors.js 中。
將所有的第三方包集中到一個(gè)文件,自然也會(huì)出現(xiàn)文件過(guò)大的問(wèn)題。
可以看到,當(dāng)前只有一個(gè) chunk 也就是 app.js ,他是一個(gè) entry chunk 。因?yàn)槲覀兊?webpack 配置是這樣子的:
java
復(fù)制代碼
// webpack.config.js module.exports = { ?entry: { ? ? app: './src/main.js', // entry chunk } }
app.js 包含了我們的第三方庫(kù) vue 和 axios ,以及我們的業(yè)務(wù)代碼 src 。
分離 Vendor,最簡(jiǎn)單方法就是:加一個(gè) entry ( File Changes ):
java
復(fù)制代碼
// webpack.config.js module.exports = { ?entry: { ? ?app: './src/main.js', ? ?vendor: ['vue', 'axios'], }, }
雖然 vendor.js 這個(gè) entry chunk 包含了我們想要的 vue 和 axios ,但是細(xì)心的同學(xué)會(huì)發(fā)現(xiàn), app.js 也包含了他們!為什么?。?/p>
其實(shí)這是很正常的事情:每個(gè) entry 都包含了他自己的依賴,這樣他才能作為一個(gè)入口,獨(dú)立地跑起來(lái)。
很難受,事實(shí)上我們并不想 app.js 還包含了 vue 和 axios 。如果可以把他們倆相同的依賴提取出來(lái)就好了,就像這樣:
SplitChunksPlugin
SplitChunksPlugin 插件可以將公共的依賴模塊提取到已有的 chunk 中,或者提取到一個(gè)新生成的 chunk。讓我們使用這個(gè)插件,將之前的示例中重復(fù)的 lodash 模塊去除:
webpack.config.js
css
復(fù)制代碼
module.exports = { entry: { // 多入口 ? index: './src/index.js', ? another: './src/another_module.js', }, output: { ? filename: '[name].bundle.js', // 對(duì)應(yīng)多個(gè)出口文件名 ? path: path.resolve(__dirname, './dist'), }, optimization: { ? splitChunks: { // 代碼分割 ? ? // include all types of chunks ? ? chunks: 'all' ? } }, } ?
使用 optimization.splitChunks 配置選項(xiàng)之后,現(xiàn)在應(yīng)該可以看出,index.bundle.js
和 another.bundle.js
中已經(jīng)移除了重復(fù)的依賴模塊。需要注意的是,插件將 lodash
分離到單獨(dú)的 chunk,并且將其從 main bundle 中移除,減輕了大小
CommonsChunkPlugin(已廢棄)
現(xiàn)在,修改我們的 webpack 配置文件( File Changes ):
php
復(fù)制代碼
new webpack.optimize.CommonsChunkPlugin({ ?name: 'vendor', })
但是!隨著業(yè)務(wù)的增長(zhǎng),我們依賴的第三方庫(kù)代碼很可能會(huì)越來(lái)越多,這時(shí)候我們的 webpack.config.js 就變成這樣了:
java
復(fù)制代碼
module.exports = { ?entry: { ? ?app: './src/main.js', ? ?vendor: [ ? ? ?'vue', ? ? ?'axio', ? ? ?'vue-router', ? ? ?'vuex', ? ? ?'element-ui', ? ? ?// 很長(zhǎng)很長(zhǎng) ? ], }, }
vendor entry 會(huì)變成很長(zhǎng)很長(zhǎng),更糟糕的是,我們每次引入了新的第三方庫(kù),都需要在 vendor 手動(dòng)增加對(duì)應(yīng)的包名。
動(dòng)態(tài)導(dǎo)入懶加載
-
import() 為動(dòng)態(tài)加載腳本,webpack 會(huì)生成類(lèi)似以上動(dòng)態(tài)創(chuàng)建
script
標(biāo)簽的代碼 - import 里的注釋為特殊含義的魔法注釋?zhuān)绻辉O(shè)置 webpackChunkName,加載的腳本將被按數(shù)字次序命名
如果我們想「按需加載」路由組件的話,只要改幾行代碼就好了。
javascript
復(fù)制代碼
//index.js setTimeout(function () { ?//文件會(huì)等5秒后加載,實(shí)現(xiàn)懶加載 ?// webpackChunkName: "dynamicImport":這是webpack動(dòng)態(tài)導(dǎo)入模塊命名的方式。 ?//瀏覽器看到的文件名:dynamicImport.chunk-test.js。output.chunkFilename配置命名格式 ?const add = () => import( ? ?/* webpackChunkName: "dynamicImport" */ ? ?'./dynamicImport.js') ?console.log(add(1, 2)); }, 5000) ? //dynamicImport.js export default function add(a,b){ ?return a+b; }
動(dòng)態(tài)import使用最多的一個(gè)場(chǎng)景是懶加載(比如路由懶加載)
- 封裝一個(gè)component.js,返回一個(gè)component對(duì)象;
- 我們可以在一個(gè)按鈕點(diǎn)擊時(shí),加載這個(gè)對(duì)象;
如果你用了 Babel ,就需要裝上這個(gè)插件@babel/plugin-syntax-dynamic-import:babel plugin syntax dynamic import 來(lái)解析 import() 語(yǔ)法。
預(yù)加載
在聲明 import 時(shí),使用下面這些內(nèi)置指令,可以讓 webpack 輸出 "resource hint(資源提示)",來(lái)告知瀏覽器:
- prefetch(預(yù)獲取):將來(lái)某些導(dǎo)航下可能需要的資源。只會(huì)緩存資源不會(huì)解析
- preload(預(yù)加載):當(dāng)前導(dǎo)航下可能需要資源。會(huì)緩存資源并解析
prefetch
下面這個(gè) prefetch 的簡(jiǎn)單示例中,有一個(gè) HomePage
組件,其內(nèi)部渲染一個(gè) LoginButton
組件,然后在點(diǎn)擊后按需加載 LoginModal
組件。
LoginButton.js
go
復(fù)制代碼
//... import(/* webpackPrefetch: true */ './path/to/LoginModal.js');
這會(huì)生成 <link rel="prefetch" href="login-modal-chunk.js">
并追加到頁(yè)面頭部,指示著瀏覽器在閑置時(shí)間預(yù)取 login-modal-chunk.js
文件。
只要父 chunk 完成加載,webpack 就會(huì)添加 prefetch hint(預(yù)取提示)。
不同
與 prefetch 指令相比,preload 指令有許多不同之處:
- preload chunk 會(huì)在父 chunk 加載時(shí),以并行方式開(kāi)始加載。prefetch chunk 會(huì)在父 chunk 加載結(jié)束后開(kāi)始加載。
- preload chunk 具有中等優(yōu)先級(jí),并立即下載。prefetch chunk 在瀏覽器閑置時(shí)下載。
- preload chunk 會(huì)在父 chunk 中立即請(qǐng)求,用于當(dāng)下時(shí)刻。prefetch chunk 會(huì)用于未來(lái)的某個(gè)時(shí)刻。
- 瀏覽器支持程度不同。
babel
動(dòng)態(tài)導(dǎo)入
如果你用了 Babel ,就需要裝上這個(gè)插件@babel/plugin-syntax-dynamic-import:babel plugin syntax dynamic import 來(lái)解析 import() 語(yǔ)法。
json
復(fù)制代碼
// .babelrc { ?"plugins": ["syntax-dynamic-import"] }
資源模塊
使用 webpack 資源模塊?(asset module) 代替舊的 assets loader(如 file-loader
/url-loader
/raw-loader
等),減少 loader 配置數(shù)量。
配置方式如下:
bash
復(fù)制代碼
module.exports = { ? rules: [ ? ? ? { ? ? ? test: /.(png|svg|jpg|jpeg|gif)$/i, ? ? ? include: [ ? ? ? ? paths.appSrc, ? ? ? ], ? ? ? type: 'asset/resource', ? ? }, ? ] }
SourceMap
最佳選擇是 eval-cheap-module-source-map
詳細(xì)區(qū)分可至 webpack devtool?查看。
css抽離
mini-css-extract-plugin插件會(huì)將 CSS 提取到單獨(dú)的文件中,為每個(gè)包含 CSS 的 JS 文件創(chuàng)建一個(gè) CSS 文件,并且支持 CSS 和 SourceMaps 的按需加載
ini
復(fù)制代碼
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); plugins: [ new MiniCssExtractPlugin({ ? ? ?filename: "css/[name].[hash].css", // 定義抽離的入口文件的文件名 ? ? ?chunkFilename: "css/[name].[hash].css", // 定義非入口塊文件的名稱(chēng),如動(dòng)態(tài)導(dǎo)入的文件 ? }) ],
css壓縮
ini
復(fù)制代碼
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); + const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); ? module.exports = { module: { ? rules: [ ? ? { ? ? ? test: /.(css|less)$/, ? ? ? use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"], ? ? }, ? ], }, + optimization: { + ? minimizer: [ + ? ? new CssMinimizerPlugin(), + ? ], + }, plugins: [new MiniCssExtractPlugin()], };
這將僅在mode: production
生產(chǎn)環(huán)境
開(kāi)啟 CSS 優(yōu)化
如果還想在開(kāi)發(fā)環(huán)境
下啟用 CSS 優(yōu)化,optimization.minimize
設(shè)置為 true
gzip壓縮
前端將文件打包成 .gz
文件,然后通過(guò) nginx
的配置,讓瀏覽器直接解析 .gz
文件,可以大大提升文件加載的速度,瀏覽器可以直接解析 .gz
文件并解壓。
javascript
復(fù)制代碼
啟用gzip壓縮(需要配置nginx,可以看出壓縮后的文件大小明顯變化) highlighter- PHP ? const CompressionWebpackPlugin = require('compression-webpack-plugin') chainWebpack(config) { // 生產(chǎn)模式下啟用gzip壓縮 需要配置nginx支持gzip ? if (process.env.NODE_ENV === 'production') { ? ? config.plugin('CompressionWebpackPlugin').use(CompressionWebpackPlugin, [ ? ? ? { ? ? ? ? filename: '[path][base].gz', ? ? ? ? algorithm: 'gzip', ? ? ? ? test: new RegExp('\.(js|css)$'), ? ? ? ? // 只處理大于xx字節(jié) 的文件,默認(rèn):0 ? ? ? ? threshold: 10240, ? ? ? ? // 示例:一個(gè)1024b大小的文件,壓縮后大小為768b,minRatio : 0.75 ? ? ? ? minRatio: 0.8, // 默認(rèn): 0.8 ? ? ? ? // 是否刪除源文件,默認(rèn): false ? ? ? ? deleteOriginalAssets: false ? ? ? } ? ? ]) ? } }
js壓縮
blog.csdn.net/qq_29722281…
-
terser-webpack-plugin和uglifyjs-webpack-plugin(不推薦)
不再維護(hù) uglify-es ,并且 uglify-js 不支持 ES6 +。
terser 是 uglify-es 的一個(gè)分支,主要保留了與 uglify-es 和 uglify-js@3 的 API 和 CLI 兼容性。
webpack5 自帶最新的
terser-webpack-plugin
,無(wú)需手動(dòng)安裝。
yamlterser-webpack-plugin
默認(rèn)開(kāi)啟了parallel: true
配置,并發(fā)運(yùn)行的默認(rèn)數(shù)量:os.cpus().length - 1
,本文配置的 parallel 數(shù)量為 4,使用多進(jìn)程并發(fā)運(yùn)行壓縮以提高構(gòu)建速度。復(fù)制代碼
const TerserPlugin = require('terser-webpack-plugin'); module.exports = { ? ?optimization: { ? ? ? ?minimizer: [ ? ? ? ? ? ?new TerserPlugin({ ? ? ? ? ? ? ?parallel: 4, ? ? ? ? ? ? ?terserOptions: { ? ? ? ? ? ? ? ?parse: { ? ? ? ? ? ? ? ? ?ecma: 8, ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ?compress: { ? ? ? ? ? ? ? ? ?ecma: 5, ? ? ? ? ? ? ? ? ?warnings: false, ? ? ? ? ? ? ? ? ?comparisons: false, ? ? ? ? ? ? ? ? ?inline: 2, ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ?mangle: { ? ? ? ? ? ? ? ? ?safari10: true, ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ?output: { ? ? ? ? ? ? ? ? ?ecma: 5, ? ? ? ? ? ? ? ? ?comments: false, ? ? ? ? ? ? ? ? ?ascii_only: true, ? ? ? ? ? ? ? }, ? ? ? ? ? ? }, ? ? ? ? ? }), ? ? ? ] ? } }
-
vue-cli
arduino復(fù)制代碼
config.optimization.minimize(true)// 開(kāi)啟壓縮js代碼 ? ? config.optimization.splitChunks({ // 開(kāi)啟代碼分割 ? ? chunks: 'all' })
img壓縮
image-minimizer-webpack-plugin:用來(lái)壓縮圖片的插件
npm i image-minimizer-webpack-plugin imagemin -D 還有剩下包需要下載,有兩種模式:
無(wú)損壓縮 npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D 有損壓縮 npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D
配置CDN
線上使用 cdn ,如何庫(kù)有問(wèn)題,項(xiàng)目就會(huì)有問(wèn)題,除非公司有自己的 cdn 庫(kù),不過(guò)這確實(shí)也是一種優(yōu)化方案,效果也還不錯(cuò)。它的配置也很簡(jiǎn)單,在 externals 中配置,例子:
arduino
復(fù)制代碼
module.exports = { ?configureWebpack: config => { ? ?if (process.env.NODE_ENV === 'production') { ? ? ?// 配置 cdn,這里將 vue,vue-router 和 axios 三個(gè)包配置成 cdn 引入 ? ? ?// 其中 Vue,VueRouter 等名稱(chēng)是該庫(kù)暴露在全局中的變量名 ? ? ?config.externals = { ? ? ? ?vue: 'Vue', ? ? ? ?'vue-router': 'VueRouter', ? ? ? ?axios: 'axios' ? ? } ? } } }
然后在 public/index.html
模板文件中引入 cdn 地址:
xml
復(fù)制代碼
<!DOCTYPE html> <html> ?<head> ? ?<meta charset="utf-8" /> ? ?<meta http-equiv="X-UA-Compatible" content="IE=edge" /> ? ?<meta name="viewport" content="width=device-width,initial-scale=1.0" /> ? ?<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> ? ?<title></title> ? ?<!-- 引入 cdn 地址 --> ? ?<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.10/vue.min.js"></script> ? ?<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.0.1/vue-router.min.js"></script> ? ?<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.18.0/axios.min.js"></script> ?</head> ?<body> ? ?<div id="app"></div> ?</body> </html>
我這里使用的是 bootcdn 的地址,需要注意版本問(wèn)題。
也可以借助 HtmlWebpackPlugin 插件來(lái)方便插入 cdn 的引入。
使用 cdn 引入的方式雖然能極大改善網(wǎng)頁(yè)加載速度,但我還是不會(huì)用這個(gè)功能,項(xiàng)目還不需要非得這樣的優(yōu)化,也怕 cdn 不穩(wěn)定。
借助 HtmlWebpackPlugin 插件來(lái)方便插入 cdn 的引入
ini
復(fù)制代碼
//生產(chǎn)環(huán)境標(biāo)記 const IS_PRODUCTION = process.env.NODE_ENV === "production"; const path = require("path"); // 生產(chǎn)配置 const cdn_production = { ?js: ["/librarys/vue@2.6.11/vue.min.js"] }; // 開(kāi)發(fā)配置 const cdn_development = { ?js: ["/librarys/vue@2.6.11/vue.js"] }; ? module.exports = { ?configureWebpack: { ? ?externals: { ? ? ?vue: "Vue", ? }, }, ?chainWebpack: config => { ? ?config.plugin("html").tap(args => { ? ? ?args[0].cdn = IS_PRODUCTION ? cdn_production : cdn_development; ? ? ?return args; ? }); } };
index.html中添加
javascript
復(fù)制代碼
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %>
按需加載
1. lodash
類(lèi)似 import { throttle } from 'lodash'
就屬于有副作用的引用,會(huì)將整個(gè) lodash 文件進(jìn)行打包。
優(yōu)化方式是使用 import { throttle } from 'lodash-es'
代替 import { throttle } from 'lodash'
, lodash-es?將 Lodash?庫(kù)導(dǎo)出為 ES?模塊,支持基于 ES modules 的 tree shaking,實(shí)現(xiàn)按需引入。
2. ant-design
ant-design?默認(rèn)支持基于 ES modules 的 tree shaking,對(duì)于 js 部分,直接引入 import { Button } from 'antd'
就會(huì)有按需加載的效果。
假如項(xiàng)目中僅引入少部分組件,import { Button } from 'antd'
也屬于有副作用,webpack不能把其他組件進(jìn)行tree-shaking。這時(shí)可以縮小引用范圍,將引入方式修改為 import { Button } from 'antd/lib/button'
來(lái)進(jìn)一步優(yōu)化。
Tree Shaking
javascript
復(fù)制代碼
tree shaking` 是一個(gè)術(shù)語(yǔ),用于描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴于 ES2015 模塊語(yǔ)法的 靜態(tài)結(jié)構(gòu) 特性,例如 `import` 和 `export
babel
Babel 為編譯的每個(gè)文件都插入了輔助代碼,使代碼體積過(guò)大!默認(rèn)情況下會(huì)被添加到每一個(gè)需要它的文件中??梢詫⑦@些輔助代碼作為一個(gè)獨(dú)立模塊,來(lái)避免重復(fù)引入。
@babel/plugin-transform-runtiome:
禁用了 Babel 自動(dòng)對(duì)每個(gè)文件的 runtime 注入,而是引入 @babel/plugin-transform-runtiome 并且使所有輔助代碼從這里引用
先下載包:
npm i @babel/plugin-transform-runtime -D
sideEffects(不推薦)
sideEffects 有三種情況
sideEffects:true 所有文件都有副作用,全都不可 tree-shaking sideEffects:false 有這些文件有副作用,所有其他文件都可以 tree-shaking,但會(huì)保留這些文件 sideEffects:[] 部分 tree-shaking , 除了數(shù)組外都 tree-shaking
"side effect(副作用)" 的定義是,在導(dǎo)入時(shí)會(huì)執(zhí)行特殊行為的代碼,而不是僅僅暴露一個(gè) export 或多個(gè) export。舉例說(shuō)明,例如 polyfill,它影響全局作用域,并且通常不提供 export。
如果你的代碼確實(shí)有一些副作用,可以改為提供一個(gè)數(shù)組:
json
復(fù)制代碼
{ ?"name": "your-project", ?"sideEffects": ["./src/some-side-effectful-file.js"] }
所有導(dǎo)入文件都會(huì)受到 tree shaking 的影響。這意味著,如果在項(xiàng)目中使用類(lèi)似 css-loader
并 import 一個(gè) CSS 文件,則需要將其添加到 side effect 列表中,以免在生產(chǎn)模式中無(wú)意中將它刪除:
json
復(fù)制代碼
{ ?"name": "your-project", ?"sideEffects": ["./src/some-side-effectful-file.js", "*.css"] }
IgnorePlugin
- 這是webpack內(nèi)置插件
- 這個(gè)插件的作用是:忽略第三方包指定目錄,讓這些指定目錄不要被打包進(jìn)去
javascript
復(fù)制代碼
//雖然我設(shè)置了語(yǔ)言為中文,但是在打包的時(shí)候,是會(huì)將所有語(yǔ)言都打包進(jìn)去的。這樣就導(dǎo)致包很大,打包速度又慢 plugins:[ new Webpack.IgnorePlugin(/./locale/,/moment/),//moment這個(gè)庫(kù)中,如果引用了./locale/目錄的內(nèi)容,就忽略掉,不會(huì)打包進(jìn)去 ]
css
打包時(shí)把沒(méi)有用的 CSS 代碼搖走,可以大幅減少打包后的 CSS 文件大小。
使用 purgecss-webpack-plugin?對(duì) CSS Tree Shaking。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-805244.html
插件
autoprefixer兼容css
webpak 引入autoprefixer,自動(dòng)加上各種前綴讓不同的瀏覽器得以支持文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-805244.html
到了這里,關(guān)于webpack/vue-cli構(gòu)建速度和打包體積優(yōu)化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!