從零開始使用 webpack5 搭建 react 項目

本文的示例項目源碼可以點擊 這裡 獲取

一、前言

webpack5 也已經發布一段時間了,其模組聯邦、bundle 快取等新特性值得在項目中進行使用。經過筆者在公司實際項目中的升級結果來看,其提升效果顯著,熱更新時間由原來的 8s 減少到了 2s,會極大的提升開發幸福感。除此之外,webpack5 也帶來了更好的 tree shaking 演算法,項目的打包體積也會進一步減少,提升用戶體驗。

目前來看,create-react-app 腳手架還沒有適配 webpack5,如果你想熟悉下如何從零開始配置 webpack5 項目的話,不妨跟著文檔操作一下。

二、項目初始化

2.1 初始化文件結構

首先創建一個文件夾,進行 npm 初始化

mkdir react-webpack5-template
cd react-webpack5-template
# npm 初始化配置
npm init -y
# 創建 webpack 配置文件
touch webpack.common.js
# 創建 babel 配置文件
mkdir src && cd src
# 創建入口文件
touch index.js
cd .. && mkdir build
touch index.html

在上述步驟執行完畢之後,你的目錄結構應該如下所示:

├── src
│   └── index.js
├── build
│   └── index.html
├── webpack.common.js
├── .babelrc
├── package.json

隨後安裝必要的依賴

npm i webpack webpack-cli webpack-dev-server html-webpack-plugin babel-loader path -D
npm i react react-dom

2.2 完善配置文件

文件結構生成完畢後,我們開始編寫程式碼。首先,在index.js 中寫入以下程式碼:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <React.StrictMode>
    <div>你好,React-webpack5-template</div>
  </React.StrictMode>,
  document.getElementById('root')
);

webpack.common.js 中寫入以下內容:

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

module.exports = (env) => {
  return {
    mode: "development",
    entry: {
      index: './src/index.js'
    },
    output: {
      // 打包文件根目錄
      path: path.resolve(__dirname, "dist/"),
    },
    plugins: [
      // 生成 index.html
      new HtmlWebpackPlugin({
        filename: "index.html",
        template: "./build/index.html",
      }),
    ],
    module: {
      rules: [
        {
          test: /\.(jsx|js)?$/,
          use: ["babel-loader"],
          include: path.resolve(__dirname, 'src'),
        },
      ]
    },
    devServer: {
      port: 8080,
      host: '0.0.0.0',
    },
  }
}

在 index.html 中寫入以下程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

在 .babalrc 中寫入以下程式碼:

{
  "presets": ["@babel/preset-react"]
}

然後在 package.json 中添加如下 script:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
+  "dev": "webpack serve --config webpack.common.js"
},

隨後我們運行 npm run dev 就可以直接運行了,由於我們上面設置的 devServer 埠號為 8080,所以在瀏覽器中打開 localhost:8080 即可看到如下效果:

image-20210228004846012

到這裡位置,我們的初步搭建已經完成了,但是我們在現有的項目中看到的 webpack 配置文件不止這些,有 less、css 文件的解析,image 等資源文件的處理,還有一些優化項的配置等,接下來會一一介紹。

三、功能性配置

上面我們已經做到可以將一個簡單的 React 項目運行起來了,接下來我們要做的是加一些功能。

3.1 樣式文件解析

在前端項目開發過程中,比較經常使用的是 css、less、scss、sass、stylus,下面我們就先僅對 less 進行配置,其餘的樣式文件可參考 GitHub 源碼。首先安裝 loader:

npm i style-loader less-loader less css-loader postcss-loader postcss-normalize autoprefixer postcss-preset-env -D

首先,在 webpack.common.js 頂部加入以下正則表達式,用來判斷樣式文件:

// less/less module 正則表達式
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

然後在 webpack.common.js 中加入以下配置:

module: {
	rules: [
    {
      test: lessRegex,
      use: ["style-loader", "css-loader", "postcss-loader", "less-loader"],
      sideEffects: true,
    },
  ]
}

新增 postcss.config.js 文件並配置:

const postcssNormalize = require('postcss-normalize');

module.exports = {
  plugins: [
    [
      "postcss-preset-env",
      {
        autoprefixer: {
          flexbox: "no-2009",
        },
        stage: 3,
      }
    ],
    postcssNormalize(),
    require('autoprefixer') ({
      overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
    })
  ],
};

然後我們在 src 目錄下新建 index.less 文件,測試配置是否成功:

// index.less
.title {
  text-align: center;
  color: coral;
}

重新運行項目後發現樣式生效,配置成功。

image-20210228102928287

但是僅配置 less 是不夠的,我們日常在開發過程中經常用到 less module,在這裡我們進行如下配置,首先安裝 react-dev-utils

npm i react-dev-utils resolve-url-loader -D

在 webpack.common.js 中進行如下配置:

const getCSSModuleLocalIdent = require("react-dev-utils/getCSSModuleLocalIdent");

module: {
	rules: [
    {
      test: lessRegex,
+     exclude: lessModuleRegex,
      use: ["style-loader", "css-loader", "postcss-loader", "less-loader"],
      sideEffects: true,
    },
+   {
+     test: lessModuleRegex,
+     use: [
+       "style-loader",
+       {
+         loader: "css-loader",
+         options: {
+           modules: {
+             getLocalIdent: getCSSModuleLocalIdent,
+           }
+         }
+       },
+       "postcss-loader",
+       "less-loader"
+     ],
+   }
  ]
}

接下來我們新建 index.module.less 來進行測試:

.font {
  color: red;
}

重新運行項目後樣式生效,並且 className 也發生了相應變化:

image-20210228110624352

CSS、SCSS 與 SASS 的配置都大同小異,大家可以移步到我的 GitHub

3.2 圖片地址解析

資源模組(asset module)是一種模組類型,它允許使用資源文件(字體,圖標等)而無需配置額外 loader。

在 webpack 5 之前,通常使用:

資源模組類型(asset module type),通過添加 4 種新的模組類型,來替換所有這些 loader:

  • asset/resource 發送一個單獨的文件並導出 URL。之前通過使用 file-loader 實現。
  • asset/inline 導出一個資源的 data URI。之前通過使用 url-loader 實現。
  • asset/source 導出資源的源程式碼。之前通過使用 raw-loader 實現。
  • asset 在導出一個 data URI 和發送一個單獨的文件之間自動選擇。之前通過使用 url-loader,並且配置資源體積限制實現。

—— 引自 webpack5 中文文檔

webpack5 內置 assets 類型,我們不需要額外安裝插件就可以進行圖片等資源文件的解析,配置如下:

{
  test: /\.(jpe?g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i,
  type: "asset/resource",
},

如此我們便可以處理引入的圖片資源文件,可以根據自身需要進行拓展。

四、性能優化

4. 1 引入快取

前面提到,webpack5 引入了快取來提高二次構建速度,我們只需要在 webpack 配置文件中加入如下程式碼即可開心快取

cache: {
  type: 'filesystem',
  // 可選配置
  buildDependencies: {
    config: [__filename], // 當構建依賴的config文件(通過 require 依賴)內容發生變化時,快取失效
  },
  name: 'development-cache',
},

重新運行項目後會發現 node_modules 目錄下會新增一個 .cache 文件夾:

image-20210228114440107

筆者在實際項目中測試,熱更新時間由原來的 8s 縮短到 2s 可以說是提升巨大。

五、總結

到目前為止,配置工作算是已經完成了,本篇文章只是指導大家進行一些初始化配置,項目中肯定還有很多可以優化的地方,比如說分別配置 webpack.dev.js 以及 webpack.prod.js 以通過測試環境與正式環境的不同需求,在這裡就不細說,環境區分的相關配置我會上傳到 GitHub 中,如果你覺得項目對你有點用處的話,還請點個 star。