<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          學習 Webpack5 之路(優(yōu)化篇)- 近 7k 字

          共 27741字,需瀏覽 56分鐘

           ·

          2021-08-27 15:22

          點擊上方 前端瓶子君,關(guān)注公眾號

          回復算法,加入前端編程面試算法每日一題群


          一、前言

          從 0 到 1 學習的朋友可參考前置學習文章:

          前置文章 學習 Webpack5 之路(基礎(chǔ)篇)[4] 對 webpack 的概念做了簡單介紹,學習 Webpack5 之路(實踐篇)[5] 則從配置著手,用 webpack 搭建了一個 SASS + TS + React 的項目。

          本篇將從優(yōu)化開發(fā)體驗、加快編譯速度、減小打包體積、加快加載速度 4 個角度出發(fā),介紹如何對 webpack 項目進行優(yōu)化。

          本文依賴的 webpack 版本信息如下:

          • webpack-cli\@4.7.2[6]
          • webpack\@5.46.0[7]

          二、優(yōu)化效率工具

          在優(yōu)化開始之前,需要做一些準備工作。

          安裝以下 webpack 插件,幫助我們分析優(yōu)化效率:

          • progress-bar-webpack-plugin[8]:查看編譯進度;
          • speed-measure-webpack-plugin[9]:查看編譯速度;
          • webpack-bundle-analyzer[10]:打包體積分析。

          1. 編譯進度條

          一般來說,中型項目的首次編譯時間為 5-20s,沒個進度條等得多著急,通過 progress-bar-webpack-plugin[11] 插件查看編譯進度,方便我們掌握編譯情況。

          安裝:

          npm i -D progress-bar-webpack-plugin
          復制代碼

          webpack.common.js 配置方式如下:

          const chalk = require('chalk')
          const ProgressBarPlugin = require('progress-bar-webpack-plugin')
          module.exports = {
            plugins: [
              // 進度條
              new ProgressBarPlugin({
                  format`  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
                })
            ],
          }
          復制代碼

          貼心的為進度百分比添加了加粗和綠色高亮態(tài)樣式。

          包含內(nèi)容、進度條、進度百分比、消耗時間,進度條效果如下:

          image.png

          2. 編譯速度分析

          優(yōu)化 webpack 構(gòu)建速度,首先需要知道是哪些插件、哪些 loader 耗時長,方便我們針對性的優(yōu)化。

          通過 speed-measure-webpack-plugin[12] 插件進行構(gòu)建速度分析,可以看到各個 loader、plugin 的構(gòu)建時長,后續(xù)可針對耗時 loader、plugin 進行優(yōu)化。

          安裝:

          npm i -D speed-measure-webpack-plugin
          復制代碼

          webpack.dev.js 配置方式如下:


          const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
          const smp = new SpeedMeasurePlugin();
          module.exports = smp.wrap({
            // ...webpack config...
          })
          復制代碼

          包含各工具的構(gòu)建耗時,效果如下:

          image.png

          注意:這些灰色文字的樣式,是因為我在 vscode 終端運行的,導致有顏色的字體都顯示為灰色,換個終端就好了,如 iTerm2[13]。

          3. 打包體積分析

          同樣,優(yōu)化打包體積,也需要先分析各個 bundle 文件的占比大小,來進行針對優(yōu)化。

          使用 webpack-bundle-analyzer[14] 查看打包后生成的 bundle 體積分析,將 bundle 內(nèi)容展示為一個便捷的、交互式、可縮放的樹狀圖形式。幫助我們分析輸出結(jié)果來檢查模塊在何處結(jié)束。

          安裝:

          npm i -D webpack-bundle-analyzer
          復制代碼

          webpack.prod.js 配置方式如下:


          const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
          module.exports = {
            plugins: [
              // 打包體積分析
              new BundleAnalyzerPlugin()
            ],
          }
          復制代碼

          包含各個 bundle 的體積分析,效果如下:

          image.png

          三、優(yōu)化開發(fā)體驗

          1. 自動更新

          自動更新[15] 指的是,在開發(fā)過程中,修改代碼后,無需手動再次編譯,可以自動編譯代碼更新編譯后代碼的功能。

          webpack 提供了以下幾種可選方式,實現(xiàn)自動更新功能:

          1. webpack's Watch Mode[16]
          2. webpack-dev-server[17]
          3. webpack-dev-middleware[18]

          webpack 官方推薦的方式是 webpack-dev-server,在 學習 Webpack5 之路(實踐篇)[19] - DevServer 章節(jié)[20] 已經(jīng)介紹了 webpack-dev-server[21] 幫助我們在代碼發(fā)生變化后自動編譯代碼實現(xiàn)自動更新的用法,在這里不重復贅述。

          這是針對開發(fā)環(huán)境的優(yōu)化,修改 webpack.dev.js 配置。

          2. 熱更新

          熱更新[22] 指的是,在開發(fā)過程中,修改代碼后,僅更新修改部分的內(nèi)容,無需刷新整個頁面。

          2.1 修改 webpack-dev-server 配置

          使用 webpack 內(nèi)置的 HMR 插件,更新 webpack-dev-server 配置。

          webpack.dev.js 配置方式如下:

          module.export = {
              devServer: {
                  contentBase'./dist',
                  hottrue// 熱更新
                },
          }
          復制代碼

          2.2 引入 react-refresh-webpack-plugin

          使用 react-refresh-webpack-plugin[23] 熱更新 react 組件。

          安裝:

          npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
          復制代碼

          webpack.dev.js 配置方式如下:


          const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

          module.exports = {
              plugins: [
                  new webpack.HotModuleReplacementPlugin(),
                  new ReactRefreshWebpackPlugin(),
              ]
          }
          復制代碼

          遇到的問題:

          配置了 SpeedMeasurePlugin 后,熱更新就無效了,會提示 runtime is undefined。

          image.png

          解決方案:

          僅在分析構(gòu)建速度時打開 SpeedMeasurePlugin 插件,這里我們先關(guān)閉 SpeedMeasurePlugin 的使用,來查看熱更新效果。

          最終效果:

          更新 react 組件代碼時,無需刷新頁面,僅更新組件部分。

          四、加快構(gòu)建速度

          1. 更新版本

          1.1 webpack 版本

          使用最新的 webpack 版本,通過 webpack 自身的迭代優(yōu)化,來加快構(gòu)建速度。

          這一點是非常有效的,如 webpack5 較于 webpack4,新增了持久化緩存、改進緩存算法等優(yōu)化,webpack5 新特性可查看 參考資料[24]

          1.2 包管理工具版本

          Node.js 、package 管理工具(例如 npm 或者 yarn)更新到最新版本,也有助于提高性能。較新的版本能夠建立更高效的模塊樹以及提高解析速度。

          本文依賴的版本信息如下:

          2. 緩存

          2.1 cache

          通過配置 webpack 持久化緩存[25] cache: filesystem,來緩存生成的 webpack 模塊和 chunk,改善構(gòu)建速度。

          簡單來說,通過 cache: filesystem 可以將構(gòu)建過程的 webpack 模板進行緩存,大幅提升二次構(gòu)建速度、打包速度,當構(gòu)建突然中斷,二次進行構(gòu)建時,可以直接從緩存中拉取,可提速 90% 左右。

          webpack.common.js 配置方式如下:

          module.exports = {
              cache: {
                type'filesystem'// 使用文件緩存
              },
          }
          復制代碼

          引入緩存后,首次構(gòu)建時間將增加 15%,二次構(gòu)建時間將減少 90%,效果如下:

          image.png

          2.2 dll ?

          webpack 官網(wǎng)構(gòu)建性能[26] 中看到關(guān)于 dll 的介紹:

          dll 可以為更改不頻繁的代碼生成單獨的編譯結(jié)果。可以提高應用程序的編譯速度。

          我興沖沖的開始尋找 dll 的相關(guān)配置說明,太復雜了,接著找到了一個輔助配置 dll 的插件 autodll-webpack-plugin[27],結(jié)果上面直接寫了 webpack5 開箱即用的持久緩存是比 dll 更優(yōu)的解決方案。

          所以,不用再配置 dll了,上面介紹的 cache 明顯更香。

          2.3 cache-loader ?

          沒錯,cache-loader[28] 也不需要引入了,上面的 cache 已經(jīng)幫助我們緩存了。

          3. 減少 loader、plugins

          每個的 loader、plugin 都有其啟動時間。盡量少地使用工具,將非必須的 loader、plugins 刪除。

          3.1 指定 include

          為 loader 指定 include,減少 loader 應用范圍,僅應用于最少數(shù)量的必要模塊,。

          webpack 構(gòu)建性能文檔[29]

          rule.exclude 可以排除模塊范圍,也可用于減少 loader 應用范圍.

          webpack.common.js 配置方式如下:

          module.exports = {
              rules: [
                  {
                      test/\.(js|ts|jsx|tsx)$/,
                      include: paths.appSrc,
                      use: [
                        {
                          loader'esbuild-loader',
                          options: {
                            loader'tsx',
                            target'es2015',
                          },
                        }
                      ]
                   }
              ]
          }
          復制代碼

          定義 loader 的 include 后,構(gòu)建時間將減少 12%,效果如下:

          image.png

          3.2 管理資源

          使用 webpack 資源模塊[30] (asset module) 代替舊的 assets loader(如 file-loader/url-loader/raw-loader 等),減少 loader 配置數(shù)量。

          配置方式如下:

          module.exports = {
              rules: [
                 {
                  test/\.(png|svg|jpg|jpeg|gif)$/i,
                  include: [
                    paths.appSrc,
                  ],
                  type'asset/resource',
                },
              ]
          }
          復制代碼

          引入資源模塊后,構(gòu)建時間將減少 7%,效果如下:

          image.png

          4. 優(yōu)化 resolve 配置

          resolve[31] 用來配置 webpack 如何解析模塊,可通過優(yōu)化 resolve 配置來覆蓋默認配置項,減少解析范圍。

          4.1 alias

          alias 可以創(chuàng)建 importrequire 的別名,用來簡化模塊引入。

          webpack.common.js 配置方式如下:

          module.exports = {
              resolve: {
                  alias: {
                    '@': paths.appSrc, // @ 代表 src 路徑
                  },
              }
          }
          復制代碼

          4.2 extensions

          extensions 表示需要解析的文件類型列表。

          根據(jù)項目中的文件類型,定義 extensions,以覆蓋 webpack 默認的 extensions,加快解析速度。

          由于 webpack 的解析順序是從左到右,因此要將使用頻率高的文件類型放在左側(cè),如下我將 tsx 放在最左側(cè)。

          webpack.common.js 配置方式如下:

          module.exports = {
              resolve: {
                  extensions: ['.tsx''.js'], // 因為我的項目只有這兩種類型的文件,如果有其他類型,需要添加進去。
              }
          }
          復制代碼

          4.3 modules

          modules 表示 webpack 解析模塊時需要解析的目錄。

          指定目錄可縮小 webpack 解析范圍,加快構(gòu)建速度。

          webpack.common.js 配置方式如下:

          module.exports = {
              modules: [
                'node_modules',
                 paths.appSrc,
              ]
          }
          復制代碼

          4.4 symlinks

          如果項目不使用 symlinks(例如 npm link 或者 yarn link),可以設(shè)置 resolve.symlinks: false,減少解析工作量。

          webpack.common.js 配置方式如下:

          module.exports = {
              resolve: {
                  symlinks: false,
              },
          }
          復制代碼

          優(yōu)化 resolve 配置后,構(gòu)建時間將減少 1.5%,效果如下:

          image.png

          5. 多進程

          上述可以看到 sass-loader 的構(gòu)建時間有 1.56s,占據(jù)了整個構(gòu)建過程的 60%,那么有沒有方法來加快 sass-loader 的構(gòu)建速度呢?

          可以通過多進程來實現(xiàn),試想將 sass-loader 放在一個獨立的 worker 池中運行,就不會阻礙其他 loader 的構(gòu)建了,可以大大加快構(gòu)建速度。

          5.1 thread-loader

          通過 thread-loader[32] 將耗時的 loader 放在一個獨立的 worker 池中運行,加快 loader 構(gòu)建速度。

          安裝:

          npm i -D thread-loader
          復制代碼

          webpack.common.js 配置方式如下:

          module.exports = {
              rules: [
                  {
                  test/\.module\.(scss|sass)$/,
                  include: paths.appSrc,
                  use: [
                    'style-loader',
                    {
                      loader'css-loader',
                      options: {
                        modulestrue,
                        importLoaders2,
                      },
                    },
                    {
                      loader'postcss-loader',
                      options: {
                        postcssOptions: {
                          plugins: [
                            [
                              'postcss-preset-env',
                            ],
                          ],
                        },
                      },
                    },
                    {
                      loader'thread-loader',
                      options: {
                        workerParallelJobs2
                      }
                    },
                    'sass-loader',
                  ].filter(Boolean),
                },
              ]
          }
          復制代碼

          webpack 官網(wǎng)[33] 提到 node-sass 中有個來自 Node.js 線程池的阻塞線程的 bug。當使用 thread-loader 時,需要設(shè)置 workerParallelJobs: 2。

          由于 thread-loader 引入后,需要 0.6s 左右的時間開啟新的 node 進程,本項目代碼量小,可見引入 thread-loader 后,構(gòu)建時間反而增加了0.19s。

          因此,我們應該僅在非常耗時的 loader 前引入 thread-loader。

          效果如下:

          image.png

          5.2 happypack ?

          happypack[34] 同樣是用來設(shè)置多線程,但是在 webpack5 就不要再使用 happypack[35] 了,官方也已經(jīng)不再維護了,推薦使用上文介紹的 thread-loader。

          6. 區(qū)分環(huán)境

          學習 Webpack5 之路(實踐篇)[36] - 模式(mode) 章節(jié)[37] 已經(jīng)介紹了 webpack 的不同模式的內(nèi)置優(yōu)化。

          在開發(fā)過程中,切忌在開發(fā)環(huán)境使用生產(chǎn)環(huán)境才會用到的工具,如在開發(fā)環(huán)境下,應該排除 [fullhash]/[chunkhash]/[contenthash] 等工具。

          同樣,在生產(chǎn)環(huán)境,也應該避免使用開發(fā)環(huán)境才會用到的工具,如 webpack-dev-server 等插件。

          7. 其他

          7.1 devtool

          不同的 devtool 設(shè)置,會導致性能差異。

          在大多數(shù)情況下,最佳選擇是 eval-cheap-module-source-map。

          詳細區(qū)分可至 webpack devtool[38] 查看。

          webpack.dev.js 配置方式如下:

          export.module = {
              devtool'eval-cheap-module-source-map',
          }
          復制代碼

          7.2 輸出結(jié)果不攜帶路徑信息

          默認 webpack 會在輸出的 bundle 中生成路徑信息,將路徑信息刪除可小幅提升構(gòu)建速度。

          module.exports = {
              output: {
                  pathinfo: false,
                },
              };
          }
          復制代碼

          四、減小打包體積

          1. 代碼壓縮

          體積優(yōu)化第一步是壓縮代碼,通過 webpack 插件,將 JS、CSS 等文件進行壓縮。

          1.1 JS 壓縮

          使用 TerserWebpackPlugin[39] 來壓縮 JavaScript。

          webpack5 自帶最新的 terser-webpack-plugin,無需手動安裝。

          terser-webpack-plugin 默認開啟了 parallel: true 配置,并發(fā)運行的默認數(shù)量:os.cpus().length \- 1 ,本文配置的 parallel 數(shù)量為 4,使用多進程并發(fā)運行壓縮以提高構(gòu)建速度。

          webpack.prod.js 配置方式如下:

          const TerserPlugin = require('terser-webpack-plugin');
          module.exports = {
              optimization: {
                  minimizer: [
                      new TerserPlugin({
                        parallel4,
                        terserOptions: {
                          parse: {
                            ecma8,
                          },
                          compress: {
                            ecma5,
                            warningsfalse,
                            comparisonsfalse,
                            inline2,
                          },
                          mangle: {
                            safari10true,
                          },
                          output: {
                            ecma5,
                            commentsfalse,
                            ascii_onlytrue,
                          },
                        },
                      }),
                  ]
              }
          }
          復制代碼

          體積減小 10%,效果如下:

          image.png

          1.1 ParallelUglifyPlugin ?

          你可能有聽過 ParallelUglifyPlugin 插件,它可以幫助我們多進程壓縮 JS,webpack5 的 TerserWebpackPlugin 默認就開啟了多進程和緩存,無需再引入 ParallelUglifyPlugin。

          1.2 CSS 壓縮

          使用 CssMinimizerWebpackPlugin[40] 壓縮 CSS 文件。

          optimize-css-assets-webpack-plugin[41] 相比,css-minimizer-webpack-plugin[42] 在 source maps 和 assets 中使用查詢字符串會更加準確,而且支持緩存和并發(fā)模式下運行。

          CssMinimizerWebpackPlugin 將在 Webpack 構(gòu)建期間搜索 CSS 文件,優(yōu)化、壓縮 CSS。

          安裝:

          npm install -D css-minimizer-webpack-plugin
          復制代碼

          webpack.prod.js 配置方式如下:

          const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

          module.exports = {
            optimization: {
              minimizer: [
                new CssMinimizerPlugin({
                    parallel4,
                  }),
              ],
            }
          }
          復制代碼

          由于 CSS 默認是放在 JS 文件中,因此本示例是基于下章節(jié)將 CSS 代碼分離后的效果。

          2. 代碼分離

          代碼分離能夠把代碼分離到不同的 bundle 中,然后可以按需加載或并行加載這些文件。代碼分離可以用于獲取更小的 bundle,以及控制資源加載優(yōu)先級,可以縮短頁面加載時間。

          2.1 抽離重復代碼

          SplitChunksPlugin[43] 插件開箱即用,可以將公共的依賴模塊提取到已有的入口 chunk 中,或者提取到一個新生成的 chunk。

          webpack 將根據(jù)以下條件自動拆分 chunks:

          • 新的 chunk 可以被共享,或者模塊來自于 node_modules 文件夾;
          • 新的 chunk 體積大于 20kb(在進行 min+gz 之前的體積);
          • 當按需加載 chunks 時,并行請求的最大數(shù)量小于或等于 30;
          • 當加載初始化頁面時,并發(fā)請求的最大數(shù)量小于或等于 30;

          通過 splitChunks 把 react 等公共庫抽離出來,不重復引入占用體積。

          注意:切記不要為 cacheGroups 定義固定的 name,因為 cacheGroups.name 指定字符串或始終返回相同字符串的函數(shù)時,會將所有常見模塊和 vendor 合并為一個 chunk。這會導致更大的初始下載量并減慢頁面加載速度。

          webpack.prod.js 配置方式如下:

          module.exports = {
              splitChunks: {
                // include all types of chunks
                chunks'all',
                // 重復打包問題
                cacheGroups:{
                  vendors:{ // node_modules里的代碼
                    test/[\\/]node_modules[\\/]/,
                    chunks"all",
                    // name: 'vendors', 一定不要定義固定的name
                    priority10// 優(yōu)先級
                    enforcetrue 
                  }
                }
              },
          }
          復制代碼

          將公共的模塊單獨打包,不再重復引入,效果如下:

          image.png

          2.2 CSS 文件分離

          MiniCssExtractPlugin[44] 插件將 CSS 提取到單獨的文件中,為每個包含 CSS 的 JS 文件創(chuàng)建一個 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加載。

          安裝:

          npm install -D mini-css-extract-plugin
          復制代碼

          webpack.common.js 配置方式如下:

          const MiniCssExtractPlugin = require("mini-css-extract-plugin");

          module.exports = {
            plugins: [new MiniCssExtractPlugin()],
            module: {
              rules: [
                  {
                  test/\.module\.(scss|sass)$/,
                  include: paths.appSrc,
                  use: [
                    'style-loader',
                    isEnvProduction && MiniCssExtractPlugin.loader, // 僅生產(chǎn)環(huán)境
                    {
                      loader'css-loader',
                      options: {
                        modulestrue,
                        importLoaders2,
                      },
                    },
                    {
                      loader'postcss-loader',
                      options: {
                        postcssOptions: {
                          plugins: [
                            [
                              'postcss-preset-env',
                            ],
                          ],
                        },
                      },
                    },
                    {
                      loader'thread-loader',
                      options: {
                        workerParallelJobs2
                      }
                    },
                    'sass-loader',
                  ].filter(Boolean),
                },
              ]
            },
          };
          復制代碼

          注意:MiniCssExtractPlugin.loader 要放在 style-loader 后面。

          效果如下:

          image.png

          2.3 最小化 entry chunk

          通過配置 optimization.runtimeChunk = true,為運行時代碼創(chuàng)建一個額外的 chunk,減少 entry chunk 體積,提高性能。

          webpack.prod.js 配置方式如下:

          module.exports = {
              optimization: {
                  runtimeChunktrue,
                },
              };
          }
          復制代碼

          效果如下:

          image.png

          3. Tree Shaking(搖樹)

          搖樹,顧名思義,就是將枯黃的落葉搖下來,只留下樹上活的葉子??蔹S的落葉代表項目中未引用的無用代碼,活的樹葉代表項目中實際用到的源碼。

          3.1 JS

          JS Tree Shaking[45] 將 JavaScript 上下文中的未引用代碼(Dead Code)移除,通過 package.json"sideEffects" 屬性作為標記,向 compiler 提供提示,表明項目中的哪些文件是 "pure(純正 ES2015 模塊)",由此可以安全地刪除文件中未使用的部分。

          Dead Code 一般具有以下幾個特征:

          • 代碼不會被執(zhí)行,不可到達;
          • 代碼執(zhí)行的結(jié)果不會被用到;
          • 代碼只會影響死變量(只寫不讀)。

          3.1.1 webpack5 sideEffects

          通過 package.json 的 "sideEffects" 屬性,來實現(xiàn)這種方式。

          {
            "name""your-project",
            "sideEffects"false
          }
          復制代碼

          需注意的是,當代碼有副作用時,需要將 sideEffects 改為提供一個數(shù)組,添加有副作用代碼的文件路徑:

          {
            "name""your-project",
            "sideEffects": ["./src/some-side-effectful-file.js"]
          }
          復制代碼

          添加 TreeShaking 后,未引用的代碼,將不會被打包,效果如下:

          image.png

          3.1.2 對組件庫引用的優(yōu)化

          webpack5 sideEffects 只能清除無副作用的引用,而有副作用的引用則只能通過優(yōu)化引用方式來進行 Tree Shaking。

          1. lodash

          類似 import { throttle } from 'lodash' 就屬于有副作用的引用,會將整個 lodash 文件進行打包。

          優(yōu)化方式是使用 import { throttle } from 'lodash-es' 代替 import { throttle } from 'lodash'lodash-es[46]Lodash[47] 庫導出為 ES[48] 模塊,支持基于 ES modules 的 tree shaking,實現(xiàn)按需引入。

          2. ant-design

          ant-design[49] 默認支持基于 ES modules 的 tree shaking,對于 js 部分,直接引入 import { Button } from 'antd' 就會有按需加載的效果。

          假如項目中僅引入少部分組件,import { Button } from 'antd' 也屬于有副作用,webpack不能把其他組件進行tree-shaking。這時可以縮小引用范圍,將引入方式修改為 import { Button } from 'antd/lib/button' 來進一步優(yōu)化。

          3.2 CSS

          上述對 JS 代碼做了 Tree Shaking 操作,同樣,CSS 代碼也需要搖搖樹,打包時把沒有用的 CSS 代碼搖走,可以大幅減少打包后的 CSS 文件大小。

          使用 purgecss-webpack-plugin[50] 對 CSS Tree Shaking。

          安裝:

          npm i purgecss-webpack-plugin -D
          復制代碼

          因為打包時 CSS 默認放在 JS 文件內(nèi),因此要結(jié)合 webpack 分離 CSS 文件插件 mini-css-extract-plugin 一起使用,先將 CSS 文件分離,再進行 CSS Tree Shaking。

          webpack.prod.js 配置方式如下:

          const glob = require('glob')
          const MiniCssExtractPlugin = require('mini-css-extract-plugin')
          const PurgeCSSPlugin = require('purgecss-webpack-plugin')
          const paths = require('paths')

          module.exports = {
            plugins: [
              // 打包體積分析
              new BundleAnalyzerPlugin(),
              // 提取 CSS
              new MiniCssExtractPlugin({
                filename"[name].css",
              }),
              // CSS Tree Shaking
              new PurgeCSSPlugin({
                paths: glob.sync(`${paths.appSrc}/**/*`,  { nodirtrue }),
              }),
            ]
          }
          復制代碼

          上面為了測試 CSS 壓縮效果,我引入了大量無效 CSS 代碼,因此 Tree Shaking 效果也非常明顯,效果如下:

          image.png

          3. CDN

          上述是對 webpack 配置的優(yōu)化,另一方面還可以通過 CDN 來減小打包體積。

          這里引入 CDN 的首要目的為了減少打包體積,因此僅僅將一部分大的靜態(tài)資源手動上傳至 CDN,并修改本地引入路徑。下文的加快加載速度,將介紹另一種 CDN 優(yōu)化手段。

          將大的靜態(tài)資源上傳至 CDN:

          • 字體:壓縮并上傳至 CDN;
          • 圖片:壓縮并上傳至 CDN。

          五、加快加載速度

          1. 按需加載

          通過 webpack 提供的 import\(\) 語法[51] 動態(tài)導入[52] 功能進行代碼分離,通過按需加載,大大提升網(wǎng)頁加載速度。

          使用方式如下:

          export default function App () {
              return (
                  <div>
                      hello react 111
                      <Hello />
                      <button onClick={() => import('lodash')}>加載lodash</button>
                  </div>

              )
          }
          復制代碼

          效果如下:

          Untitled.gif

          2. 瀏覽器緩存[53]

          瀏覽器緩存,就是進入某個網(wǎng)站后,加載的靜態(tài)資源被瀏覽器緩存,再次進入該網(wǎng)站后,將直接拉取緩存資源,加快加載速度。

          webpack 支持根據(jù)資源內(nèi)容,創(chuàng)建 hash id,當資源內(nèi)容發(fā)生變化時,將會創(chuàng)建新的 hash id。

          配置 JS bundle hash,webpack.common.js 配置方式如下:

          module.exports = {
            // 輸出
            output: {
              // 僅在生產(chǎn)環(huán)境添加 hash
              filename: ctx.isEnvProduction ? '[name].[contenthash].bundle.js' : '[name].bundle.js',
            },
          }
          復制代碼

          配置 CSS bundle hash,webpack.prod.js 配置方式如下:

          module.exports = {
            plugins: [
              // 提取 CSS
              new MiniCssExtractPlugin({
                filename"[hash].[name].css",
              }),
            ],
          }
          復制代碼

          配置 optimization.moduleIds,讓公共包 splitChunks 的 hash 不因為新的依賴而改變,減少非必要的 hash 變動,webpack.prod.js 配置方式如下:

          module.exports = {
            optimization: {
              moduleIds'deterministic',
            }
          }
          復制代碼

          通過配置 contenthash/hash,瀏覽器緩存了未改動的文件,僅重新加載有改動的文件,大大加快加載速度。

          3. CDN

          將所有的靜態(tài)資源,上傳至 CDN,通過 CDN 加速來提升加載速度。

          webpack.common.js 配置方式如下:

          export.modules = {
          output: {
              publicPath: ctx.isEnvProduction ? 'https://xxx.com' : ''// CDN 域名
            },
          }
          復制代碼

          六、優(yōu)化前后對比

          在倉庫代碼僅 webpack 配置不同的情況下,查看優(yōu)化前后對比。

          • 優(yōu)化前 github 地址
          • 優(yōu)化后 github 地址

          1. 構(gòu)建速度

          類型首次構(gòu)建未修改內(nèi)容二次構(gòu)建修改內(nèi)容二次構(gòu)建
          優(yōu)化前2.7s2.7s2.7s
          優(yōu)化后2.7s0.5s0.3s
          image.png
          image.png

          2. 打包體積

          類型體積大小
          優(yōu)化前250 kb
          優(yōu)化后231 kb
          image.png

          七、總結(jié)

          從上章節(jié) [優(yōu)化前后對比] 可知,在小型項目中,添加過多的優(yōu)化配置,作用不大,反而會因為額外的 loader、plugin 增加構(gòu)建時間。

          在加快構(gòu)建時間方面,作用最大的是配置 cache,可大大加快二次構(gòu)建速度。

          在減小打包體積方面,作用最大的是壓縮代碼、分離重復代碼、Tree Shaking,可最大幅度減小打包體積。

          在加快加載速度方面,按需加載、瀏覽器緩存、CDN 效果都很顯著。

          本篇就介紹到這兒啦,有更好的 webpack 優(yōu)化方式歡迎評論區(qū)告訴我哦~

          本文源碼:

          • webpack Demo2 優(yōu)化前[54]
          • webpack Demo2 優(yōu)化后[55]

          希望能對你有所幫助,感謝閱讀~

          別忘了點個贊鼓勵一下我哦,筆芯??


          關(guān)于本文

          來源:清湯餃子

          https://juejin.cn/post/6996816316875161637

          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?

          回復「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會很認真的解答喲!
          回復「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
           》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 47
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美熟女一区 | 亚洲一级毛 | 久久免费国产视频 | 国产爆乳肥臀在线观看 | 久久免费高清 |