【webpack系列】從零搭建 webpack4+react 腳手架(五)


本章節,我們一起來探討以下問題:如何對編譯后的文件進行gzip壓縮,如何讓開發環境的控制台輸出更加高逼格,如何更好的對編譯后的文件進行bundle分析等。

1 gzip壓縮

如果你想節省帶寬提高網站速度,壓縮是一種簡單有效的方法。我們模擬一次html的請求,想象一下瀏覽器和服務器的對話:

  1. 瀏覽器:嘿,給我來一個 index.html文件
  2. 服務器:好的,讓我去找找它是不是在~
  3. 服務器:找到它了,我會返回一個成功的狀態碼(200 ok),我正在發送文件……
  4. 瀏覽器:100kb? 我滴天……等啊……等啊,好的,下載下來了

那現在問題在哪呢?

好吧,這系統是正常的,但是太低效了,坦白講100kb是一大段的文字,HTML是冗余的,每一個標簽都有一個幾乎相同的閉合標簽。雖然通篇文字都有重復,但是只要你砍掉任何的內容,html都不會正常顯示。

當文件太大的時候有什么好辦法呢,就是gzip壓縮它。

如果我們傳輸一個替代原始大文件的zip的壓縮文件給瀏覽器,就會節省帶寬和下載時間。當瀏覽器可以下載zip文件,解壓,並且渲染給用戶。下載很快,頁面加載也很快。現在,這個瀏覽器–服務器的會話大概是這樣的:

  1. 瀏覽器:嘿,給我來一個index.html,如果要有,給我來一個壓縮版的可以嗎
  2. 服務器:容我找找……好,滿足你
  3. 服務器:yep,找到了,馬上傳給你。
  4. 瀏覽器:太棒了,只有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內即可。支持傳入一個配置對象,相關說明:

  1. filename 壓縮后的文件名
  2. algorithm 算法 默認gzip
  3. test 針對文件的正則表達式規則,符合規則的文件被壓縮
  4. threshold 文件大於這個值的會被壓縮
  5. 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

觀察終端的輸出,是不是漂亮了很多。當然你可以自己定制輸出的內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM