<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>

          webpack 最佳實(shí)踐

          共 31545字,需瀏覽 64分鐘

           ·

          2021-07-12 03:56

          前言

          本文講述的最佳實(shí)踐是從日常業(yè)務(wù)中總結(jié)而出的,不一定適合所有項(xiàng)目。畢竟每個公司或個人的項(xiàng)目不同,最佳實(shí)踐也會有所不同。但是可以從這篇文章借鑒吸收一點(diǎn)有用的東西,有問題的地方也歡迎大家積極吐槽指正

          為了避免出現(xiàn) 我這明明可以,你那怎么不行 的尷尬情況,這里列一下文章涉及到依賴的版本號。

          ├── webpack           5.39.1
          ├── webpack-cli       4.7.2
          ├── node              12.8.0
          ├── npm               6.10.2

          正文

          初始化項(xiàng)目

          1. mkdir test-app && cd test-app
          2. npm init

          首先添加一個入口文件 /src/index.js 和 webpack 配置文件 webpack.config.js,現(xiàn)在我們的目錄結(jié)構(gòu)如下

          test-app
              ├── src
              |    └── index.js
              ├── package.json
              ├── webpack.config.js

          安裝 webpack

          npm install webpack webpack-cli -D

          開始搞事情

          src/index.js 中隨便寫點(diǎn)東西

          class Test {
            constructor() {
              document.writeTest('hello world')
            }
          }

          new Test()

          先來打個包看看啥效果, 執(zhí)行命令 npx webpack

          1.png

          等待一段時間后,看到目錄有了變化, 新增了一個 dist 目錄,該目錄下有一個 main.js 文件

          test-app
            + ├── dist
            + |    └── main.js
              ├── src
              |    └── index.js
              ├── package.json
              ├── webpack.config.js

          讓我們來看看 main.js 里有點(diǎn)啥

          new class{constructor(){document.writeTest("hello world")}};

          這玩意都不用試,肯定不得行啊,得將 js 代碼轉(zhuǎn)成 es5 才行。首先安裝下babel-loader及幾個相關(guān)的依賴

          配置 babel

          • babel-loader
          • @babel/core
          • @babel/preset-env
          • @babel/plugin-transform-runtime
          • @babel/plugin-proposal-decorators
          • @babel/plugin-proposal-class-properties
          • @babel/plugin-proposal-private-methods
          • @babel/runtime
          • @babel/runtime-corejs3
          npm install babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime  @babel/plugin-proposal-decorators  @babel/plugin-proposal-class-properties @babel/plugin-proposal-private-methods -D
          npm install @babel/runtime @babel/runtime-corejs3 -s

          修改 webpack.config.js 文件, 添加 babel-loader 配置

          const path = require('path');

          module.exports = {
            entry'./src/index.js',
            output: {
              path: path.resolve(__dirname, 'dist'),
              filename'bundle.[contenthash:8].js',
            },
            module: {
              rules: [
                {
                  test/\.(jsx|js)$/,
                  use'babel-loader',
                  exclude/node_modules/,
                },
              ]
            }
          }

          根目錄下添加相應(yīng)的 .babelrc 配置文件

          {
              "presets": ["@babel/preset-env"],
              "plugins": [
                  ["@babel/plugin-transform-runtime", {"corejs"3}],
                  ["@babel/plugin-proposal-decorators", { "legacy"true }],
                  ["@babel/plugin-proposal-class-properties", { "loose"true }],
                  ["@babel/plugin-proposal-private-methods", { "loose"true }]
              ]
          }

          再次執(zhí)行命令 npx webpack 來打個包。完成后查看目錄結(jié)構(gòu)

          test-app
              ├── dist
            + |    ├── bundle.b8ba1739.js
              |    ├── main.js
              ├── src
              |    └── index.js
            + ├── .babelrc
              ├── package.json
              ├── webpack.config.js

          查看構(gòu)建后的 bundle.b8ba1739.js 文件

          (()=>{"use strict";new function n(){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),document.writeTest("hello world")}})();

          構(gòu)建產(chǎn)物看著沒什么問題了,接下來看下在瀏覽器中的實(shí)際效果。要看效果,肯定離不開 html 文件。

          瀏覽器中觀看效果

          作為一個伸手黨直接從社區(qū)嫖來一個插件 html-webpack-plugin,這個插件的作用是將打包產(chǎn)物引入到我們提前準(zhǔn)備好的模板 .html 文件中,我們訪問這個文件就能直觀的看到效果了

          先來安裝下插件

          npm install html-webpack-plugin -D

          接著創(chuàng)建一個 public 目錄, 用來存放靜態(tài)資源。新增一個 index.html 模板,放在 public 目錄下

          test-app
              ├── dist
              |    ├── bundle.b8ba1739.js
              |    ├── main.js
              ├── src
              |    └── index.js
            + ├── public
            + |    └── index.html
              ├── .babelrc
              ├── package.json
              ├── webpack.config.js

          webpack.config.js 中配置 html-webpack-plugin

          // 省略 ...
          const HtmlWebpackPlugin = require('html-webpack-plugin');

          module.exports = {
            // 省略 ...
            plugins: [
              new HtmlWebpackPlugin({
                template: path.resolve(__dirname, './public/index.html'),
                inject'body',
                scriptLoading'blocking',
              }),
            ]
          }

          再次執(zhí)行命令 npx webpack 來打個包。打完包發(fā)現(xiàn) dist 目錄下多了一個 index.html 文件。瀏覽器中打開 index.html 看看對不對

          2.png

          作為一個 api 工程師,連 api 都能記錯。

          3.png

          修改下 src/index.js 代碼

          class Test {
            constructor() {
              document.write('hello world')
            }
          }

          new Test()

          再次執(zhí)行命令 npx webpack 來打個包。老步驟,先檢查下打包產(chǎn)物對不對

          test-app
              ├── dist
              |    ├── bundle.b8ba1739.js
           +  |    ├── bundle.dc044571.js
              |    ├── index.html
              |    ├── main.js
              ├── src
              |    └── index.js
              ├── public
              |    └── index.html
              ├── .babelrc
              ├── package.json
              ├── webpack.config.js

          看樣子應(yīng)該沒錯,代碼修改了,打包后多了個 .js 文件。再看看效果對不對

          4.png

          界面上也出現(xiàn)了 hello world。到這里為止,算是利用 webpack 走通了一個最小流程。

          為什么說是最小,因?yàn)榈侥壳盀橹惯@個配置在實(shí)際工作中 基本沒卵用 實(shí)用性不大。細(xì)心一點(diǎn)的人已經(jīng)看出來了,上面存在三個問題

          1. 每修改一次代碼,都要走一遍打包流程,然后自己手動打開 html 文件,預(yù)覽效果
          2. 第一次調(diào)用錯誤 api 的時候,報(bào)錯信息定位不精確
          3. 打包目錄下面 上次構(gòu)建產(chǎn)物 也仍舊存在,時間長了會存在越來越多的無用代碼

          作為一個懶人,第三點(diǎn)可以忍,第一點(diǎn)和第二點(diǎn)忍不了。我們一個個來解決

          實(shí)時更新并預(yù)覽效果

          針對第一點(diǎn),查閱 webpack 官網(wǎng),發(fā)現(xiàn)官網(wǎng)就給指了一條明路

          5.png

          按照官網(wǎng)教程,首先安裝下 webpack-dev-server

          npm install webpack-dev-server -D

          再在 webpack.config.js 中添加相應(yīng)的配置

          // 省略 ...
          module.exports = {
            // 省略 ...
            devServer: {
              port'3001'// 默認(rèn)是 8080
              hottrue,
              stats'errors-only'// 終端僅打印 error
              compresstrue// 是否啟用 gzip 壓縮
              proxy: {
                '/api': {
                  target'http://0.0.0.0:80',
                  pathRewrite: {
                    '/api''',
                  },
                },
              },
            },
          }

          package.json > script 中添加一個命令

          "dev""webpack serve  --open",

          執(zhí)行 npm run dev,這個時候在動在瀏覽器中打開了 http://localhost:3001/ 頁面。光自動打開還不夠啊,我們的目標(biāo)是每次修改后不用構(gòu)建就能在瀏覽器中實(shí)時查看。為了測試這個功能是否生效,我們?nèi)我庑薷?src/index.js 文件并保存。發(fā)現(xiàn)瀏覽器中內(nèi)容自動刷新生效了。

          想了解更多關(guān)于 devServer 的可以閱讀以下兩篇文章

          • 【W(wǎng)ebpack】devServer 實(shí)驗(yàn)報(bào)告
          • 120 行代碼幫你了解 Webpack 下的 HMR 機(jī)制

          sourcemap 配置

          第一個問題好了,再來看看第二個問題 報(bào)錯信息定位不精確。我們?nèi)耘f在官網(wǎng)找找看,有沒有對應(yīng)的解決方案。通過 1 小時的文檔閱讀和 7 小時的摸魚,終于在一天后找到了解決方法。

          我們在 webpack.config.js 中添加配置

          // 省略 ...
          module.exports = {
            // 省略 ...
            devtool'eval-cheap-module-source-map',
          }

          這個配置什么意思呢,它會告訴我們錯誤是在原始代碼的哪一行發(fā)生的。廢話不多說,先來看看效果

          6.png

          點(diǎn)進(jìn)去看看是什么情況

          28.png
          7.png

          這么精準(zhǔn)的定位,一天可以改100個 bug 了。

          但是!!!這玩意好歸好,生產(chǎn)環(huán)境可不能亂用。這里建議

          開發(fā)環(huán)境 最佳:eval-cheap-module-source-map生產(chǎn)環(huán)境 最佳:hidden-source-map

          什么?你上下嘴皮子吧嗒一合,說最佳就最佳?沒有拿得出手的理由我們是不會信的

          8.png

          造謠是不可能造謠的,這輩子都不會。我也是吸收了這篇文章 萬字長文:關(guān)于 sourcemap,這篇文章就夠了 的精華才總結(jié)出來的。

          一萬字的文章總結(jié)成兩句話,10 秒鐘吸收

          9.png

          世事總是這么奇妙,按照上面的思路,在解決第二個問題的時候又帶出了一個新的問題,某些配置可能需要區(qū)分環(huán)境來設(shè)置,不同的環(huán)境設(shè)置合適的配置。就像在解決一個bug A的過程中,發(fā)現(xiàn)了一個新的 bug B。看來在解決上面第三個問題之前,得先解決這個 區(qū)分環(huán)境配置 的問題了。

          拆分環(huán)境

          按照一般慣例,我們會有 開發(fā)測試預(yù)發(fā)生產(chǎn)幾個環(huán)境。但是我個人很多情況下 開發(fā)測試 環(huán)境是同一套配置,所以我這里直接省略 測試 這個環(huán)境。

          修改下目錄結(jié)構(gòu)

          test-app
            + ├── build
            + |    ├── webpack.base.js
            + |    ├── webpack.dev.js
            + |    ├── webpack.pre.js
            + |    ├── webpack.pro.js
              ├── dist
              ├──  ├── bundle.b8ba1739.js
              ├──  ├── bundle.dc044571.js
              |    ├── index.html
              |    ├── main.js
              ├── src
              |    └── index.js
              ├── public
              |    └── index.html
              ├── .babelrc
              ├── package.json

          從目錄中就可以看出一點(diǎn)東西,我們刪除了原先根目錄下的 webpack.config.js 文件。新增了一個 build 目錄。在 build 目錄下我們需要建一個 webpack.base.js 文件。用來存放各個環(huán)境公共的配置,畢竟不可能所有配置在各個環(huán)境中都不一樣。然后按照我們各自項(xiàng)目實(shí)際的需求來建立不同環(huán)境的配置文件。

          先修改公共配置文件 webpack.base.js。原先的 devServe 配置由于只有開發(fā)環(huán)境有;devtool 各個環(huán)境不一樣,所以這兩個配置從公共配置里移除了

          const path = require('path');
          const HtmlWebpackPlugin = require('html-webpack-plugin');

          const rootDir = process.cwd();

          module.exports = {
            entry: path.resolve(rootDir, 'src/index.js'),
            output: {
              path: path.resolve(rootDir, 'dist'),
              filename'bundle.[contenthash:8].js',
            },
            module: {
              rules: [
                {
                  test/\.(jsx|js)$/,
                  use'babel-loader',
                  include: path.resolve(rootDir, 'src'),
                  exclude/node_modules/,
                },
              ]
            },
            plugins: [
              new HtmlWebpackPlugin({
                template: path.resolve(rootDir, 'public/index.html'),
                inject'body',
                scriptLoading'blocking',
              }),
            ],
          }

          接下來配置各個環(huán)境的配置,這里主要用到一個 webpack-merge 插件,用來合并公共配置,執(zhí)行 npm install webpack-merge -D

          修改 webpack.dev.js

          const { merge } = require('webpack-merge');
          const baseConfig = require('./webpack.base');

          module.exports = merge(baseConfig, {
            mode'development',
            devtool'eval-cheap-module-source-map',
            devServer: {
              port'3001'// 默認(rèn)是 8080
              hottrue,
              stats'errors-only'// 終端僅打印 error
              compresstrue// 是否啟用 gzip 壓縮
              proxy: {
                '/api': {
                  target'http://0.0.0.0:80',
                  pathRewrite: {
                    '/api''',
                  },
                },
              },
            },
          });

          因?yàn)檫@里不涉及到實(shí)際的項(xiàng)目開發(fā),所以這里預(yù)發(fā)生產(chǎn)兩個環(huán)境的文件先配置成一樣的,大家可以根據(jù)自己的實(shí)際需要來進(jìn)行不同的配置。

          • webpack.pre.js
          • webpack.pro.js
          const { merge } = require('webpack-merge');
          const baseConfig = require('./webpack.base');

          module.exports = merge(baseConfig, {
            mode'production',
            devtool'hidden-source-map',
          });

          看到仔細(xì)的人已經(jīng)發(fā)現(xiàn),配置中多了一個 mode 屬性,這個會在后面解釋一波,這里先不講

          修改 package.json 中的命令

            "scripts": {
              "dev""webpack serve --config build/webpack.dev.js --open",
              "build:pro""npx webpack --config build/webpack.pro.js",
            },

          再次執(zhí)行 npm run dev 看看效果

          10.png

          看來是沒問題了,現(xiàn)在已經(jīng)成功把 webpack.config.js 文件根據(jù)環(huán)境進(jìn)行拆分成了多個文件。

          現(xiàn)在來回顧下之前提出的第三個問題

          11.png

          這個項(xiàng)目小的時候其實(shí)問題不大,但是當(dāng)項(xiàng)目大了之后,每次打包都增加幾百上千的文件,還是有點(diǎn)恐怖的。所以還是把這個問題也順帶解決下好了。

          打包時清除上次構(gòu)建產(chǎn)物

          我們的目標(biāo)是每次打包時刪除上次打包的產(chǎn)物,保證打包目錄下所有文件都是新的,社區(qū)查找一番后,找到一個插件clean-webpack-plugin ,來看下這個插件的介紹

          12.png

          比較懶,所以直接上截圖了。老步驟,先安裝 npm install clean-webpack-plugin -D 然后直接將文檔中的示例代碼借鑒到我們的項(xiàng)目中。修改 webpack.base.js

          // 省略...
          const { CleanWebpackPlugin } = require('clean-webpack-plugin');

          module.exports = {
            // 省略...
            plugins: [
              new HtmlWebpackPlugin({
                template: path.resolve(rootDir, 'public/index.html'),
                inject'body',
                scriptLoading'blocking',
              }),
              new CleanWebpackPlugin(),
            ],
          }

          試下效果,執(zhí)行 npm run build:pro 打個包。查看目錄

          test-app
              ├── build
              |    ├── webpack.base.js
              |    ├── webpack.dev.js
              |    ├── webpack.pre.js
              |    ├── webpack.pro.js
              ├── dist
              |    ├── bundle.fd44c2eb.js
              |    ├── bundle.fd44c2eb.js.map
              |    ├── index.html
              ├── src
              |    └── index.js
              ├── public
              |    └── index.html
              ├── .babelrc
              ├── package.json

          dist 目錄下原先存在的 main.jsbundle.b8ba1739.js 等前幾次打包產(chǎn)物已經(jīng)自動清除了。到這里第三個問題也解決了

          功能完善

          添加 css 和 less 支持

          為什么不添加 sass 支持?因?yàn)槲也挥?sass

          首先,在 src 目錄下添加一個 index.less 文件

          .test {
            color: red;
          }

          修改 src/index.js 文件,在文件中引用剛才添加的 less 文件

          import './index.less'

          class Test {
            constructor() {
              this.renderDiv()
            }

            renderDiv() {
              const div = document.createElement('div')
              div.className = 'test'
              div.innerHTML = 'hello world'
              document.body.appendChild(div)
            }
          }

          new Test()

          執(zhí)行 npm run dev

          等待 10 分鐘后,頁面遲遲沒有加載任何東西,打開控制臺一看

          13.png

          英語 8 級的我立馬讀懂了報(bào)錯:"你 可能 需要 一個 什么什么 loader 來 處理 這個 文件 類型, 目前 沒有 loaders 被配置 來 process 這個 文件"

          再結(jié)合官網(wǎng)的說明

          14.png

          到了這里,我好像隱約明白了 webpack 的真諦:雖然很多時候我不行,但是很多大佬會讓我行。呸,什么叫不行?這叫 靈活可插拔,正是這種特性,讓 webpack 可靈活支持各種復(fù)雜場景的自定義配置。

          忘了正事兒,既然問題找到了,就好解決了,找到幾個處理 cssless 的 loader 就行

          首先安裝 loader

          npm install less style-loader css-loader less-loader -D

          再修改 webpack.base.js 文件

          // 省略...

          module.exports = {
            // 省略...
            module: {
              rules: [
                // 省略...
                {
                  test/\.(le|c)ss$/,
                  exclude/node_modules/,
                  use: ['style-loader''css-loader''less-loader']
                },
              ]
            },
            // 省略...
          }

          再次執(zhí)行 npm run dev,查看效果

          15.png

          css module

          這一塊是基于上面的模塊修改的,解決 css 命名混亂和沖突的。不需要的話可以直接跳過這一塊。

          修改 webpack.base.js

          // 省略...

          module.exports = {
            // 省略...
            module: {
              rules: [
                //  省略...
                {
                  test/\.(le|c)ss$/,
                  exclude/node_modules/,
                  use: [
                    'style-loader',
                    {
                      loader'css-loader',
                      options: {
                        modules: {
                          compileType'module',
                          localIdentName"[local]__[hash:base64:5]",
                        },
                      },
                    },
                    'less-loader'
                  ]
                },
              ]
            },
            // 省略...
          }

          執(zhí)行 npm run dev 來看看效果

          16.png

          class 樣式名稱后加上一個哈希串,具體的配置可以看 css-loader 官網(wǎng)

          css 自動添加前綴

          首先安裝插件

          npm install autoprefixer postcss postcss-loader -D

          修改 webpack.base.js 配置文件

          // 省略...
          const autoprefixer = require('autoprefixer');

          module.exports = {
            // 省略...
            module: {
              rules: [
                // 省略...
                {
                  test/\.(le|c)ss$/,
                  exclude/node_modules/,
                  use: [
                    // 省略...
                    'less-loader',
                    {
                      loader'postcss-loader',
                      options: {
                        postcssOptions: {
                          plugins: [
                            ["autoprefixer"],
                          ],
                        },
                      },
                    }
                  ]
                },
              ]
            },
            // 省略...
          }

          打包后抽離 css 文件

          首先安裝 mini-css-extract-plugin 插件

          npm install mini-css-extract-plugin -D

          修改 webpack.base.js 配置文件

          // 省略...
          const MiniCssExtractPlugin = require('mini-css-extract-plugin');

          module.exports = {
            // 省略...
            module: {
              rules: [
                // 省略...
                {
                  test/\.(le|c)ss$/,
                  exclude/node_modules/,
                  use: [
                    MiniCssExtractPlugin.loader,
                    // 省略...
                  ]
                },
              ]
            },
            plugins: [
              // 省略...
              new MiniCssExtractPlugin({
                filename'css/[name].css',
              }),
            ],
          }

          執(zhí)行 npm run build:pro 打個包看看效果。

          17.png

          可以看到 css 已經(jīng)被抽離出來了

          壓縮打包后的 css 文件

          首先安裝 optimize-css-assets-webpack-plugin 插件

          npm install optimize-css-assets-webpack-plugin -D

          修改 webpack.base.js 配置文件

          // 省略...
          const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');

          module.exports = {
            // 省略...
            plugins: [
              // 省略...
              new MiniCssExtractPlugin({
                filename'css/[name].css',
              }),
              new OptimizeCssPlugin(),
            ],
          }

          執(zhí)行 npm run build:pro 打個包看看效果。

          .test__1PSRs{color:red;transition-duration:.4s}

          可以看出 css 已經(jīng)被壓縮了

          復(fù)制靜態(tài)資源到打包目錄

          有些時候有些第三方的 js 插件沒有提供 npm 包,只提供了一個 cdn 地址或者一份文件需要自己下載下來。通常我們下載下來之后放在我們的 public/js 目錄下面,然后 public/index.html 文件里直接用 script 標(biāo)簽引入。這個時候不管是 npm run dev 開發(fā)時,還是 npm run build:pro 構(gòu)建后,這個 js 文件都是找不到的。我們可以嘗試下

          public/js 新加一個 test.js 的空文件,啥內(nèi)容都不用。然后在 public/index.html 中引入這個文件

          <!DOCTYPE html>
          <html lang="en">
            <head>
              // 省略
            </head>

            <body>
              <div id="root"></div>
              <script src="./js/test.js"></script>
            </body>
          </html>

          執(zhí)行 npm run dev 查看效果

          18.png

          這里我們可以用 copy-webpack-plugin 這個插件,在構(gòu)建的時候,將 public/js 的靜態(tài)資源復(fù)制到 dist 目錄下,這樣文件就能找到了

          安裝插件 npm install copy-webpack-plugin -D

          修改 webpack.base.js 配置文件

          // 省略...
          const CopyWebpackPlugin = require('copy-webpack-plugin');

          const rootDir = process.cwd();

          module.exports = {
            // 省略...
            plugins: [
              new HtmlWebpackPlugin({
                template: path.resolve(rootDir, 'public/index.html'),
                inject'body',
                scriptLoading'blocking',
              }),
              new CleanWebpackPlugin(),
              new CopyWebpackPlugin({
                patterns: [
                  {
                    from'*.js',
                    context: path.resolve(rootDir, "public/js"),
                    to: path.resolve(rootDir, 'dist/js'),
                  },
                ],
              })
              new MiniCssExtractPlugin({
                filename'css/[name].css',
              }),
              new OptimizeCssPlugin(),
            ],
          }

          執(zhí)行 npm run dev 查看效果

          19.png

          靜態(tài)文件已經(jīng)可以正常加載了。

          資源加載器

          項(xiàng)目中難免要引入一些圖標(biāo)、圖片等資源,在不做任何處理的情況下,我們嘗試下在代碼中引用圖片,修改 src/index.js 文件如下

          import wuhanjiayou from '../public/asset/a.jpeg'

          class Test {
            constructor() {
              this.renderImg()
            }

            renderImg() {
              const img = document.createElement('img')
              img.src = wuhanjiayou
              document.body.appendChild(img)
            }
          }

          new Test()

          執(zhí)行 npm run dev 看下效果,報(bào)了個熟悉的錯

          20.png

          按照以往的套路,直接引用社區(qū)的三件套 raw-loaderurl-loaderfile-loader,安裝依賴,配置依賴,一通操作下來就解決了問題。現(xiàn)在我們使用 webpack5就方便多了,不用安裝任何依賴,直接修改 webpack.base.js 配置文件

          // 省略...
          rules: [
              {
                  test/\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                  type'asset',
              },
          ]

          沒錯,就是這么簡單。type 屬性還有其他幾個值,具體可以看 官方文檔

          配置已經(jīng)修改好了,執(zhí)行 npm run dev 再來看下效果

          21.png

          搞定!

          上面講到的東西基本夠小項(xiàng)目的日常開發(fā)需求了,常用的 loader 和 plugin 都已經(jīng)有所涉及。但是,如果你的項(xiàng)目特別復(fù)雜,需求又比較小眾,社區(qū)沒有現(xiàn)成的 loader 和 plugin 可以借鑒,那么只能自己動手實(shí)現(xiàn)一個了。

          22.png

          可能在一部分人眼中,loader 和 plugin 是比較神秘的,也不可能想著自己去造一個輪子。但是當(dāng)碰到問題又沒有現(xiàn)成的解決方案的時候,那就不得不自己造了。

          看了這篇文章 Webpack - 手把手教你寫一個 loader / plugin 應(yīng)該能很快上手

          項(xiàng)目優(yōu)化

          剛才也講到了,上面的一通操作基本夠小項(xiàng)目開發(fā)使用了。為什么是小項(xiàng)目?大項(xiàng)目不行嗎?當(dāng)一個項(xiàng)目大到路由都有幾百個的時候,一次熱更新就需要十幾二十多秒,一次打包要半個小時。開發(fā)時,一次代碼改動保存就要等 20 秒,這擱誰誰都忍不了啊。這個時候就需要想點(diǎn)辦法來優(yōu)化。

          loader 配置優(yōu)化

          這個其實(shí)上面已經(jīng)做了。明確告訴 loader,哪些文件不用做處理(exclude),或者只處理哪些文件(include)。

          {
              test/\.(jsx|js)$/,
              use'babel-loader',
              // include: [path.resolve(rootDir, 'src')]
              // exclude: /node_modules/,
            },

          一般傾向于使用 include,但是如果怕漏處理一些文件的話,粗暴點(diǎn),使用 exclude: /node_modules/ 也可以。

          這部分測試了下,提升速度不是很明顯,應(yīng)該算錦上添花吧

          緩存

          先說下 webpack5 之前是怎么做的。

          利用 cache-loader 將結(jié)果緩存中磁盤中;利用 hard-source-webpack-plugin 將結(jié)果緩存在 node_modules/.cache 下提升二次打包速度;利用 DllReferencePlugin 將變化不頻繁的第三方庫提前單獨(dú)打包成動態(tài)鏈接庫,提升真正業(yè)務(wù)代碼的打包速度

          webpack5 自帶了持久化緩存,配置如下

          開發(fā)環(huán)境 webpack.dev.js

          cache: {
              type'memory'
          },

          生產(chǎn)環(huán)境 webpack.pro.js

          cache: {
              type'filesystem',
              buildDependencies: {
                config: [__filename]
              }
          },

          這個測試了下前后的打包時間

          23.png
          24.png

          數(shù)據(jù)是這個數(shù)據(jù):

          • 第一次: 12592 ms
          • 第二次: 920 ms但是我心里默數(shù)了下,二次打包大概在 3 秒左右,咱也不知道控制臺的計(jì)時邏輯是什么
          25.png

          如果在構(gòu)建時,你主動確定要放棄舊的緩存的話,可以傳一個新的 version 參數(shù)來放棄使用緩存

          cache: {
              type'filesystem',
              buildDependencies: {
                config: [__filename]
              },
              version'new_version'
          },

          代碼拆分

          optimization: {
              splitChunks: {
                chunks'all',
              }
          }

          這個在 mode: production 時是默認(rèn)開啟的,但是默認(rèn)情況下只會對按需加載的代碼進(jìn)行分割。如果我們要對一開始就加載的代碼也做分割處理,就要進(jìn)行如上配置。

          從官網(wǎng)截了一張圖:

          26.png

          大家的項(xiàng)目可能都有所不同,相對應(yīng)的最佳的配置可能也有所不同,所以這里就補(bǔ)貼具體的配置了,大家有需要的可以看官網(wǎng)的文檔對自己的項(xiàng)目進(jìn)行配置 官網(wǎng) optimization.splitChunks 更多配置、「Webpack」從 0 到 1 學(xué)會 code splitting

          mode

          mode: production 在上面出現(xiàn)了這么多次,也沒有具體說有哪些功能。其實(shí)當(dāng)設(shè)置 mode: production 時,webpack 已經(jīng)默認(rèn)開啟了一些優(yōu)化措施。

          27.png

          這里面的一些東西由于篇幅較大也不做一一說明了,反正只要記得 mode: production 已經(jīng)給我們做了一系列優(yōu)化,真的想知道有哪些優(yōu)化的,我找了篇文章,有興趣的可以看看 mode 詳解

          happypack

          利用 happypack 插件進(jìn)行多線程打包,按照官網(wǎng)文檔進(jìn)行配置

          // 省略...
          const Happypack = require('happypack');
          const os = require('os')
          const happyThreadPool = Happypack.ThreadPool({ size: os.cpus().length })

          // 省略...
          rules: [
            {
              test/\.(jsx|js)$/,
              // use: 'babel-loader',
              use'Happypack/loader?id=js',
              exclude/node_modules/,
            },
          ]

          plugins: [
              new Happypack({
                id'js'// 這個 id 值為上面 Happypack/loader?id=js 問號后跟的參數(shù)
                use: ['babel-loader'],
                threadPool: happyThreadPool
              }),
          ]

          由于本篇文章寫的是個 demo,沒有業(yè)務(wù)代碼,所以這個打包出來的時間基本沒變化甚至還多了 1 秒,這里就不貼效果圖了。這是因?yàn)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">happypack執(zhí)行也需要時間,如果項(xiàng)目比較小的話,就不需要配置了。js 處理完之后那就是要處理css了, 按照處理js的方式,ctrl+c/ctrl+v 處理css

          執(zhí)行 npm run build:pro

          ERROR in ./src/index.less
          Module build failed (from ./node_modules/Happypack/loader.js):
          Error: You forgot to add 'mini-css-extract-plugin' plugin (i.e. `{ plugins: [new MiniCssExtractPlugin()] }`), please read https://github.com/webpack-contrib/mini-css-extract-plugin#getting-started

          報(bào)錯說忘記添加了mini-css-extract-plugin插件,但是明明已經(jīng)添加了,經(jīng)過試驗(yàn),發(fā)現(xiàn)是 mini-css-extract-plugin 這個插件引起 happypack 報(bào)錯的。終于,在經(jīng)過 百度谷歌 等一系列騷操作后,我放棄了,沒找到解決方法

          尷尬.png

          現(xiàn)在擺在面前的就三條路:

          • 放棄使用 happypack
          • 使用 happypack 優(yōu)化jscss,放棄使用 mini-css-extract-plugin
          • 使用 happypack 優(yōu)化 js,放棄優(yōu)化 css,保留 mini-css-extract-plugin

          知道咋解決的或有更好的方式的可以在下方留言,讓我白嫖 借鑒下。

          thread-loader

          如果采用上面第一種,放棄使用 happypack,可以用 thread-loader 代替下。而且這個配置非常簡單。

          先安裝: npm install thread-loader -D,再修改配置

          // 省略...
          rules: [
            {
              test/\.(jsx|js)$/,
              use: ['thread-loader''babel-loader'],
              exclude/node_modules/,
            },
            {
              test/\.(le|c)ss$/,
              exclude/node_modules/,
              use: [
                MiniCssExtractPlugin.loader,
                'thread-loader',
                {
                  loader'css-loader',
                  options: {
                    modules: {
                      compileType'module',
                      localIdentName"[local]__[hash:base64:5]",
                    },
                  },
                },
                'less-loader',
                {
                  loader'postcss-loader',
                  options: {
                    postcssOptions: {
                      plugins: [
                        ["autoprefixer"],
                      ],
                    },
                  },
                }
              ],
            },
          ]

          到這里應(yīng)該可以應(yīng)付一般的項(xiàng)目了。由于這篇文章主要講述 webpack 的應(yīng)用,所以很多知識點(diǎn)沒有細(xì)講,也沒有精力細(xì)講,但是很多涉及到的知識點(diǎn)都推薦了相應(yīng)的文章,有興趣的朋友可以看一下。

          參考文獻(xiàn):

          • webpack5
          • webpack4 升級到 5


          請你喝杯?? 記得三連哦~

          1.閱讀完記得給?? 醬點(diǎn)個贊哦,有?? 有動力

          2.關(guān)注公眾號前端那些趣事,陪你聊聊前端的趣事

          3.文章收錄在Github frontendThings 感謝Star?

          瀏覽 70
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  非洲大屌操逼 | 超碰碰人人| 色色婷婷五月天 | 18禁成人黄色 | 亚洲国产操逼 |