webpack 最佳實踐

前言

本文講述的最佳實踐是從日常業務中總結而出的,不一定適合所有項目。畢竟每個公司或個人的項目不同,最佳實踐也會有所不同。但是可以從這篇文章借鑑吸收一點有用的東西,有問題的地方也歡迎大家積極吐槽指正

爲了避免出現 我這明明可以,你那怎麼不行 的尷尬情況,這裏列一下文章涉及到依賴的版本號。

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

正文

初始化項目

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

首先添加一個入口文件 /src/index.js 和 webpack 配置文件 webpack.config.js,現在我們的目錄結構如下

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

安裝 webpack

npm install webpack webpack-cli -D

開始搞事情

src/index.js 中隨便寫點東西

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

new Test()

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

1.png

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

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

讓我們來看看 main.js 裏有點啥

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

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

配置 babel

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/,
      },
    ]
  }
}

根目錄下添加相應的 .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 }]
    ]
}

再次執行命令 npx webpack 來打個包。完成後查看目錄結構

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

查看構建後的 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")}})();

構建產物看着沒什麼問題了,接下來看下在瀏覽器中的實際效果。要看效果,肯定離不開 html 文件。

瀏覽器中觀看效果

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

先來安裝下插件

npm install html-webpack-plugin -D

接着創建一個 public 目錄, 用來存放靜態資源。新增一個 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',
    }),
  ]
}

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

2.png

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

3.png

修改下 src/index.js 代碼

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

new Test()

再次執行命令 npx webpack 來打個包。老步驟,先檢查下打包產物對不對

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

看樣子應該沒錯,代碼修改了,打包後多了個 .js 文件。再看看效果對不對

4.png

界面上也出現了 hello world。到這裏爲止,算是利用 webpack 走通了一個最小流程。

爲什麼說是最小,因爲到目前爲止這個配置在實際工作中 基本沒卵用 實用性不大。細心一點的人已經看出來了,上面存在三個問題

  1. 每修改一次代碼,都要走一遍打包流程,然後自己手動打開 html 文件,預覽效果

  2. 第一次調用錯誤 api 的時候,報錯信息定位不精確

  3. 打包目錄下面 上次構建產物 也仍舊存在,時間長了會存在越來越多的無用代碼

作爲一個懶人,第三點可以忍,第一點和第二點忍不了。我們一個個來解決

實時更新並預覽效果

針對第一點,查閱 webpack 官網,發現官網就給指了一條明路

5.png

按照官網教程,首先安裝下 webpack-dev-server

npm install webpack-dev-server -D

再在 webpack.config.js 中添加相應的配置

// 省略 ...
module.exports = {
  // 省略 ...
  devServer: {
    port: '3001', // 默認是 8080
    hot: true,
    stats: 'errors-only', // 終端僅打印 error
    compress: true, // 是否啓用 gzip 壓縮
    proxy: {
      '/api'{
        target: 'http://0.0.0.0:80',
        pathRewrite: {
          '/api''',
        },
      },
    },
  },
}

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

"dev""webpack serve  --open",

執行 npm run dev,這個時候在動在瀏覽器中打開了 http://localhost:3001/ 頁面。光自動打開還不夠啊,我們的目標是每次修改後不用構建就能在瀏覽器中實時查看。爲了測試這個功能是否生效,我們任意修改 src/index.js 文件並保存。發現瀏覽器中內容自動刷新生效了。

想了解更多關於 devServer 的可以閱讀以下兩篇文章

sourcemap 配置

第一個問題好了,再來看看第二個問題 報錯信息定位不精確。我們仍舊在官網找找看,有沒有對應的解決方案。通過 1 小時的文檔閱讀和 7 小時的摸魚,終於在一天後找到了解決方法。

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

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

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

6.png

點進去看看是什麼情況

28.png

7.png

這麼精準的定位,一天可以改100個 bug 了。

但是!!!這玩意好歸好,生產環境可不能亂用。這裏建議

開發環境 最佳:eval-cheap-module-source-map生產環境 最佳:hidden-source-map

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

8.png

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

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

9.png

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

拆分環境

按照一般慣例,我們會有 開發測試預發生產幾個環境。但是我個人很多情況下 開發測試 環境是同一套配置,所以我這裏直接省略 測試 這個環境。

修改下目錄結構

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

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

先修改公共配置文件 webpack.base.js。原先的 devServe 配置由於只有開發環境有;devtool 各個環境不一樣,所以這兩個配置從公共配置裏移除了

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',
    }),
  ],
}

接下來配置各個環境的配置,這裏主要用到一個 webpack-merge 插件,用來合併公共配置,執行 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', // 默認是 8080
    hot: true,
    stats: 'errors-only', // 終端僅打印 error
    compress: true, // 是否啓用 gzip 壓縮
    proxy: {
      '/api'{
        target: 'http://0.0.0.0:80',
        pathRewrite: {
          '/api''',
        },
      },
    },
  },
});

因爲這裏不涉及到實際的項目開發,所以這裏預發生產兩個環境的文件先配置成一樣的,大家可以根據自己的實際需要來進行不同的配置。

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

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

看到仔細的人已經發現,配置中多了一個 mode 屬性,這個會在後面解釋一波,這裏先不講

修改 package.json 中的命令

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

再次執行 npm run dev 看看效果

10.png

看來是沒問題了,現在已經成功把 webpack.config.js 文件根據環境進行拆分成了多個文件。

現在來回顧下之前提出的第三個問題

11.png

這個項目小的時候其實問題不大,但是當項目大了之後,每次打包都增加幾百上千的文件,還是有點恐怖的。所以還是把這個問題也順帶解決下好了。

打包時清除上次構建產物

我們的目標是每次打包時刪除上次打包的產物,保證打包目錄下所有文件都是新的,社區查找一番後,找到一個插件clean-webpack-plugin ,來看下這個插件的介紹

12.png

比較懶,所以直接上截圖了。老步驟,先安裝 npm install clean-webpack-plugin -D 然後直接將文檔中的示例代碼借鑑到我們的項目中。修改 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(),
  ],
}

試下效果,執行 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 等前幾次打包產物已經自動清除了。到這裏第三個問題也解決了

功能完善

添加 css 和 less 支持

爲什麼不添加 sass 支持?因爲我不用 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()

執行 npm run dev

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

13.png

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

再結合官網的說明

14.png

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

忘了正事兒,既然問題找到了,就好解決了,找到幾個處理 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']
      },
    ]
  },
  // 省略...
}

再次執行 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'
        ]
      },
    ]
  },
  // 省略...
}

執行 npm run dev 來看看效果

16.png

class 樣式名稱後加上一個哈希串,具體的配置可以看 css-loader 官網

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',
    }),
  ],
}

執行 npm run build:pro 打個包看看效果。

17.png

可以看到 css 已經被抽離出來了

壓縮打包後的 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(),
  ],
}

執行 npm run build:pro 打個包看看效果。

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

可以看出 css 已經被壓縮了

複製靜態資源到打包目錄

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

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

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

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

執行 npm run dev 查看效果

18.png

這裏我們可以用 copy-webpack-plugin 這個插件,在構建的時候,將 public/js 的靜態資源複製到 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(),
  ],
}

執行 npm run dev 查看效果

19.png

靜態文件已經可以正常加載了。

資源加載器

項目中難免要引入一些圖標、圖片等資源,在不做任何處理的情況下,我們嘗試下在代碼中引用圖片,修改 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()

執行 npm run dev 看下效果,報了個熟悉的錯

20.png

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

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

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

配置已經修改好了,執行 npm run dev 再來看下效果

21.png

搞定!

上面講到的東西基本夠小項目的日常開發需求了,常用的 loader 和 plugin 都已經有所涉及。但是,如果你的項目特別複雜,需求又比較小衆,社區沒有現成的 loader 和 plugin 可以借鑑,那麼只能自己動手實現一個了。

22.png

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

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

項目優化

剛纔也講到了,上面的一通操作基本夠小項目開發使用了。爲什麼是小項目?大項目不行嗎?當一個項目大到路由都有幾百個的時候,一次熱更新就需要十幾二十多秒,一次打包要半個小時。開發時,一次代碼改動保存就要等 20 秒,這擱誰誰都忍不了啊。這個時候就需要想點辦法來優化。

loader 配置優化

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

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

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

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

緩存

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

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

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

開發環境 webpack.dev.js

cache: {
    type: 'memory'
},

生產環境 webpack.pro.js

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

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

23.png

24.png

數據是這個數據:

25.png

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

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

代碼拆分

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

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

從官網截了一張圖:

26.png

大家的項目可能都有所不同,相對應的最佳的配置可能也有所不同,所以這裏就補貼具體的配置了,大家有需要的可以看官網的文檔對自己的項目進行配置 官網 optimization.splitChunks 更多配置、「Webpack」從 0 到 1 學會 code splitting

mode

mode: production 在上面出現了這麼多次,也沒有具體說有哪些功能。其實當設置 mode: production 時,webpack 已經默認開啓了一些優化措施。

27.png

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

happypack

利用 happypack 插件進行多線程打包,按照官網文檔進行配置

// 省略...
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 問號後跟的參數
      use: ['babel-loader'],
      threadPool: happyThreadPool
    }),
]

由於本篇文章寫的是個 demo,沒有業務代碼,所以這個打包出來的時間基本沒變化甚至還多了 1 秒,這裏就不貼效果圖了。這是因爲happypack執行也需要時間,如果項目比較小的話,就不需要配置了。js 處理完之後那就是要處理css了, 按照處理js的方式,ctrl+c/ctrl+v 處理css

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

報錯說忘記添加了mini-css-extract-plugin插件,但是明明已經添加了,經過試驗,發現是 mini-css-extract-plugin 這個插件引起 happypack 報錯的。終於,在經過 百度谷歌 等一系列騷操作後,我放棄了,沒找到解決方法

尷尬. png

現在擺在面前的就三條路:

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

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"],
            ],
          },
        },
      }
    ],
  },
]

到這裏應該可以應付一般的項目了。由於這篇文章主要講述 webpack 的應用,所以很多知識點沒有細講,也沒有精力細講,但是很多涉及到的知識點都推薦了相應的文章,有興趣的朋友可以看一下。

參考文獻:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/f7Syl4pPiijUTSNUWms75A