iT邦幫忙

2023 iThome 鐵人賽

DAY 3
0
Modern Web

React 走出新手村 系列 第 3

React 走出新手村-包版工具的設定

  • 分享至 

  • xImage
  •  

有多少人從create-react-app換去使用vite了呢?在早期的教學影片當中,常常會看到講師使用create-react-app 開啟新的專案,導致後期的調整不太會使用,因為通常結尾也只是簡單的下 build 的指令而已,至於該如何調整webpack的部分,在新手階段,調整 webpack 通常都不會是我們的工作,但在走出新手村之後,這部分的概念就是必須搞懂的過程。

理解包版工具

首先,我們必須要有基礎的理解,webpack到底幫我們處理了什麼?
https://ithelp.ithome.com.tw/upload/images/20230901/20129020SRxzvEmSLM.png
webpack作為一個 JavaScript 的 Bundle 工具,用於將多個 JavaScript 檔案和相關資源打包成單一的檔案,以減少網頁載入時間並提高應用程式的效能,Bundle 就如同他翻譯意思「捆綁」一樣,將多個模組或檔案合併成一個捆綁檔案,使瀏覽器只需下載和載入單一檔案,而不是多個分散的檔案。

當然,也有其他的打包工具,例如:parcel, rollup, gulp….,但這裡主要分享業界普遍標準 webpack 要怎麼處理 React 的專案設定。

CRA(creact-react-app)的底層也用webpack作為包版工具,但他的問題如下:

  1. 太多相依性套件安裝在專案當中,使的專案檔案變得很慢。
  2. webpack config 需要透過其他的 plugin 才能做細部的調整。
  3. eject 的處理很不直觀,使用過後每次更新都要改成手動模式更新。
  4. 測試工具一大包,有些時候我們可能只需要用到 jest 或是直接透過e2e的階段測試,但多了react-testing library就是很佔資源的東西。

那麼早期的專案是怎麼透過webpack設定的呢?

這就回歸了一個基本的概念 — 瀏覽器的支援,基本上目前都有支援到 ES6,少部分版本是 ES5+ 但會逐漸淘汰,但為了保險起見通常會透過babel轉譯,就是把你那些寫好給人看的code進行壓縮,轉成瀏覽器能運行的code。同理,html & css也能通過設定做壓縮,包含檔案存放路徑的調整,甚至能做到code splitting的功能,但這前提是能自由的操控webpack,下面我就演示一下透過webpack來做React的基本設定。

請不要忘記我們前端構成的主要三元素檔案 — Html / Css / Javascript,這個在接下來的步驟當中可以幫助你記得你在幹嘛?我們的目的是壓縮這三個元素的檔案。

  • 步驟 1 — 專案初始化
// 在你專案的根目錄下
npm init --y
// or
yarn init --y

// 安裝 typescript (optional)
npm i tascript ts-loader --save-dev
// or
yarn add tascript ts-loader --dev

npx tsc --init
  • 步驟 2 — 安裝 webpack 工具
npm i webpack webpack-cli webpack-dev-server --save-dev
// or
yarn add webpack webpack-cli webpack-dev-server --dev
  • 步驟 3 — 安裝 babel 工具(for *.js檔案)
npm i babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime @babel/preset-react --save-dev
// or
yarn add babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime @babel/preset-react --dev
  • 步驟 4 — 安裝 Html & Css loader (for .html/.css 檔案)
npm i html-webpack-plugin css-loader style-loader postcss-loader postcss postcss-preset-env --save-dev
// or
yarn add html-webpack-plugin css-loader style-loader postcss-loader postcss postcss-preset-env --dev
  • 步驟 5 — 安裝 React & tailwind(自行評估是否需要tailwind, 也許成員麻瓜多可以考慮其他的component library)
npm i react react-dom tailwindcss --save
// or
yarn add react react-dom tailwindcss

// 如果是使用typescript的朋友要記得多處理以下
npm i @types/react @types/react-dom --save-dev
// or
yarn add @types/react @types/react-dom --dev
  • 步驟 6 — 於根目錄下設定webpack.config.js檔案,這裡就是調整你的打包設定,其實每個設定都可以在webpack的官方文件中找到詳細設定方式,我這邊就不再贅述太多細節,主要還是以基礎設置為主。
// webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  // 這裡不想使用typescript的朋友可以考慮用回.jsx檔名
  entry: "./src/index.tsx",
  output: {
    publicPath: "http://localhost:3000/",
  },
  resolve: {
    extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
  },

  devServer: {
    port: 3000,
    historyApiFallback: true,
  },

  module: {
    rules: [
      {
        test: /\.m?js/,
        type: "javascript/auto",
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.(css|s[ac]ss)$/i,
        // 這裡不想用tailwind的朋友可以不用設定和載入postcss-loader
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },

  plugins: [
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
  ],
};
  • 步驟 7— 於根目錄下設定.babelrc檔案調整載入 babel-loader 的設定
{
  "presets": ["@babel/preset-react", "@babel/preset-env"],
  "plugins": [
     ["@babel/transform-runtime"]
  ]
}
  • 步驟 8 — 一樣是選擇性的,設定 Tailwind & typescript 如果沒有要使用的話可以直接往下一步執行:
// 先長出tailwind.config.js
npx tailwindcss init

讓我們將長出來的tailwind.config.js檔案調整成以下:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

接著,於根目錄下新增postcss.config.js檔案如下:

const tailwindcss = require("tailwindcss");

module.exports = {
  plugins: ["postcss-preset-env", tailwindcss],
};

再來,我們調整一下tsconfig.json檔案

{
  "compilerOptions": {
    "allowUnreachableCode": false,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "jsx": "react",
    "esModuleInterop": true,
    "allowJs": true,
    "checkJs": true,
    "isolatedModules": true
  },
  "include": ["src/**/**/*"],
  "exclude": ["node_modules", "dist"]
}
  • 步驟 9 — 創建我們的 html, jsx, css 檔案,根據上面的 webpack 設定,我們會將 source code 統一放在 src 資料夾下,也就是說我們的 code 統一需要放在 src 資料夾下他才會將檔案進行壓縮,所以請先於根目錄下創建 src 資料夾,並於該資料夾下作以下設定。

那我們按照常理先來設定index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Webpack React</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

接著我們來設定index.tsx或是index.jsx

import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.scss';
import App from './App';

const rootEl = document.querySelector("#app");
if (!rootEl) throw new Error("Cannot find app element with that id");
const root = createRoot(rootEl)
// 可以使用 root 物件來渲染對應的元件,並加上嚴格模式
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

加上index.scss檔案,這裡只是示範,當然你可以改用一般Css檔案,如果是使用 tailwind 如下設定:

@tailwind base;
@tailwind components;
@tailwind utilities;

最後如往常一樣設定App.tsx或者App.jsx

import React from "react";

const App = () => {

  return (
    <div className="container mx-auto">
      <h2 className="text-primary text-4xl font-bold">Hello webpack</h2>
    </div>
  )
}

export default App;
  • 步驟 10 — 設定package.json檔案的 script 如下:
{
  "name": "wp-react-18-ts",
  "version": "1.0.0",
  // 通常會放在這個位置
  "scripts": {
    "build": "webpack --mode production",
    "start": "webpack serve --open --mode development"
  },
  // ...省略
}
  • 步驟 11 — 在終端機下指令啟動
npm run start
// or
yarn start

總結

基本上這些設定在各大包板工具中都大同小異,但我會說 webpack 比較有歷史,不管是資源還是支援他都能勝任現在的任務,就算是其他新興的工具,也都是以他為模板目標,盡量讓大家能無痛移轉,所以能學會 webpack 可以說是很重要的技能。

當然,我相信 vite, rspack, turbopack …, 這類的 build tool 更加普及了以 後,會更少人使用 webpack,因為不管是處理速度、壓縮比例、效能…,都會有很大的提升,如果底層語言是以 Rust, go, zig…, 這些高效能的語言來處理的話,本身以 nodejs 為基礎開發的 webpack 會有很難越過的坎。

但如果你也在業界工作,你會發現很多老專案都是採用 webpack 來處理的,再加上他完整的資源與歷史累積下來的市佔,就算真的遇到 bug,要想透過chatGPT 或是 stack Overflow 找到解答,應該都不會是件難事。

那麼今天的內容就到這裡,下一篇我們來回顧 React 的發展歷史。

給全新手的大禮包

React基本Hook教學


上一篇
React 走出新手村-架構和渲染模式
下一篇
React 走出新手村-回顧發展歷史
系列文
React 走出新手村 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言