【webpack系列】從零搭建 webpack4+react 腳手架(五)
1 gzip壓縮本章節,我們一起來探討以下問題:如何對編譯後的檔案進行gzip壓縮,如何讓開發環境的控制檯輸出更加高逼格,如何更好的對編譯後的檔案進行bundle分析等。
如果你想節省頻寬提高網站速度,壓縮是一種簡單有效的方法。我們模擬一次html的請求,想象一下瀏覽器和伺服器的對話:
- 瀏覽器:嘿,給我來一個 index.html檔案
- 伺服器:好的,讓我去找找它是不是在~
- 伺服器:找到它了,我會返回一個成功的狀態碼(200 ok),我正在傳送檔案……
- 瀏覽器:100kb? 我滴天……等啊……等啊,好的,下載下來了
那現在問題在哪呢?
好吧,這系統是正常的,但是太低效了,坦白講100kb是一大段的文字,HTML是冗餘的,每一個標籤都有一個幾乎相同的閉合標籤。雖然通篇文字都有重複,但是隻要你砍掉任何的內容,html都不會正常顯示。
當檔案太大的時候有什麼好辦法呢,就是gzip壓縮它。
如果我們傳輸一個替代原始大檔案的zip的壓縮檔案給瀏覽器,就會節省頻寬和下載時間。當瀏覽器可以下載zip檔案,解壓,並且渲染給使用者。下載很快,頁面載入也很快。現在,這個瀏覽器–伺服器的會話大概是這樣的:
- 瀏覽器:嘿,給我來一個index.html,如果要有,給我來一個壓縮版的可以嗎
- 伺服器:容我找找……好,滿足你
- 伺服器:yep,找到了,馬上傳給你。
- 瀏覽器:太棒了,只有10kb,我來解壓,並且渲染給使用者。
情況很簡單:檔案越小,下載更快,使用者感受更好。下面我們講講通過webpack如何對檔案進行gzip壓縮。
(1)前期準備
開啟gzip壓縮,需要在webpack配置檔案中新增一個plugin,而我們希望把是否開啟gzip壓縮做成可配置化,也就是說,這個gzip的plugin可以選擇新增也可以不新增。
我們在config.js中的build下新增一個配置項,取名為productionGzip
productionGzip:true,
另外,我們還需要修改下webpack.prod.conf.js。首先我們把原來export出來的配置物件放一個變數webpackConfig中,這樣,我們可以後續訪問的到plugins陣列,並且可以追加plugin。稍微修改webpack.prod.conf.js,就像這樣:
const webpackConfig=merge(baseWebpackConfig, { mode: 'production', output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash:16].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true, cssModule:config.base.cssModule, cssModuleExcludePath:config.base.cssModuleExcludePath }) }, plugins: [ new HtmlWebpackPlugin({ template: config.build.index, inject: 'body', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, }), new CleanWebpackPlugin([config.build.assetsRoot], { allowExternal: true }), //匯出css new MiniCssExtractPlugin({ filename: utils.assetsPath('css/[name].[hash].css'), chunkFilename: utils.assetsPath('css/[id].[hash].css'), }), ], optimization: { minimizer: [ new UglifyJSPlugin(), new OptimizeCSSAssetsPlugin({ cssProcessorOptions: true ? { map: { inline: false } } : {} }) ], splitChunks: { chunks: "all", minChunks: 1, cacheGroups: { framework: { priority: 200, test: "framework", name: "framework", enforce: true, reuseExistingChunk: true }, vendor: { priority: 10, test: /node_modules/, name: "vendor", enforce: true, reuseExistingChunk: true } } } } }); if (config.build.productionGzip) { //新增gzip壓縮外掛 } module.exports = webpackConfig;
(2)新增gzip壓縮外掛
安裝gzip外掛:compression-webpack-plugin
npm i compression-webpack-plugin --save-dev
(3)使用外掛
使用只要把CompressionWebpackPlugin的例項物件追加到plugins內即可。支援傳入一個配置物件,相關說明:
- filename 壓縮後的檔名
- algorithm 演算法 預設gzip
- test 針對檔案的正則表示式規則,符合規則的檔案被壓縮
- threshold 檔案大於這個值的會被壓縮
- minRatio 壓縮率 預設0.8
要配置test,我們在config.js的build屬性下新增加一個配置項,取名productionGzipExtensions,是一個數組,定義了那些字尾的檔案要被壓縮。
productionGzipExtensions: ['js', 'css'],
然後這樣通過正則表示式:
new RegExp('\\.(' + config.build.productionGzipExtensions.join('|') + ')$')
配置的字尾會符合規則被gzip壓縮。
在webpack.prod.conf.js詳細的配置如下:
if (config.build.productionGzip) { const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ filename: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) ) }
執行命令檢視:
npm run build
檢視編譯後生成的js,多了.gz檔案,這個就是gzip壓縮後的檔案,把它們上傳到伺服器,並且伺服器開啟gzip的功能即可。
bundle分析工具 編譯後,我們不能直觀地知道那些元件被編譯到哪些檔案中。通過bundle分析工具,可以直觀地看清楚這個問題。好處是幫助我們更好地優化程式碼和改進編譯。
(1) 安裝webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
(2)配置是否啟用的引數
在config.js檔案的build屬性下增加配置項bundleAnalyzerReport,用來表示是否開啟分析。這個變數會不停修改,所以我們希望會在npm命令後面加上--report 就表示最後啟動bundle分析,不加就不會啟動bundle分析。怎麼做?通過process.env.npm_config_report可以獲取到npm命令的配置
bundleAnalyzerReport: process.env.npm_config_report
(3)使用
在webpack.prod.conf.js增加如下程式碼:
if (config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) }
(4)執行命令
分別以下2個執行試試看吧
npm run build
npm run build --report
通過增加--report 編譯成功後會啟動Webpack Bundle Analyzer。預設是http://127.0.0.1:8888。你可以直觀看到每個檔案有哪些模組被編譯進去。
美化終端的提示 在編譯過程中,我們希望在終端能給出提示,編譯成功給出我們自定義的一些說明。
(1)ora和chalk
這裡需要介紹2個npm庫。ora是一個能讓你在終端提示狀態的庫,chalk是方便我們美化輸出的文字。
我們先安裝這2個庫。
npm i --save-dev ora chalk
(2)修改編譯的方法
看看我們原先的build方法,開啟package.json,在scripts屬性下找到build屬性,可以看到它的值是
webpack --config build/webpack.prod.conf.js
通過webpack命令在終端去編譯,我們無法獲取webpack的編譯狀態,webpack還提供了webpack方法,通過webpack方法編譯,編譯結束可以執行回撥函式。我們需要美化終端的顯示,希望在編譯中能顯示編譯的狀態,編譯結束提示編譯成功,很有必要修改成通過webpack方法來編譯。
在build目錄下新增加一個build.js檔案:內容如下:
const ora = require('ora'); const chalk = require('chalk') const webpack = require('webpack') const webpackConfig = require('./webpack.prod.conf'); const spinner = ora('編譯中...\n').start(); webpack(webpackConfig, function (err, stats) { if (err) { spinner.fail("編譯失敗"); console.log(err); return; } spinner.succeed('編譯已結束. \n'); process.stdout.write(stats.toString({ colors: true, modules: false, children: false, chunks: false, chunkModules: false }) + '\n\n'); console.log(chalk.cyan(' 編譯成功!\n')) console.log(chalk.yellow( ' 提示: 編譯後的檔案可以上傳並且部署到伺服器\n' + ' 通過file:// 開啟index.html不會起作用.\n' )) })
stats是編譯結束後webpack回調回來的引數,包含了編譯後的檔案資訊。
修改package.json的build屬性:
"build": "node build/build.js",
最後重新執行編譯命令看看吧
npm run build
觀察終端的輸出,是不是漂亮了很多。當然你可以自己定製輸出的內容。