終究都要學 React 何不現在學呢? - React Vite - Vite 淺談與 GitHub 部署 - (23)

前言

前一章節已經將原本在 Create React App 的環境轉移到 Vite 了,所以接下來會稍微簡單認識為什麼 Vite 這麼快的原因與如何將專案部署到 GitHub Pages 上。

CRA 轉移 Vite

前一篇寫完之後我才想到我少講了一段關於轉移的部分,所以前面就稍微提一下轉移的部分。

其實移轉到 Vite 過程很簡單,因為我們當前開發環境並沒有很複雜,前一篇也已經安裝好相關要使用的套件跟設定了,因此剩下來的就是將原本在 Create React App 的東西轉移到 Vite 而已。

像是將 CRA 的 App.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { useState, useEffect } from 'react';

import List from './components/List';

const App = () => {
const [ todoList, setTodoList ] = useState(JSON.parse(localStorage.getItem('todoList')) || []);

const addTodo = (event) => {
setTodoList([
...todoList,
{
id: Date.now(),
name: event.target.previousElementSibling.value,
status: false
}
]);
event.target.previousElementSibling.value = '';
};

useEffect(() => {
localStorage.setItem('todoList', JSON.stringify(todoList));
}, [ todoList ]);

const remoteAllTodo = () => {
setTodoList([]);
};

return (
<div>
<div className="bg-indigo-500 p-5 h-screen">
<div className="max-w-[768px] m-auto bg-white p-5">
<h1 className="text-center text-2xl mb-4">React ToDoList</h1>
<div className="flex">
<input type="text" className="w-full rounded-l-lg border-l-2 border-y-2 border-indigo-300 pl-4 focus:outline-indigo-500 focus:outline-none focus:outline-offset-0" placeholder="請輸入你的代辦事項" />
<button onClick={ addTodo } className="w-[50px] h-[50px] border-0 bg-sky-500 hover:bg-sky-600 rounded-r-lg text-white transition duration-700">+</button>
</div>

<List todoList={ todoList } setTodoList={ setTodoList }/>

<div className="flex justify-between items-center mt-5">
<p>
目前有 <span className="font-medium">{ todoList.length }</span> 個事項待完成
</p>

<button onClick={ remoteAllTodo } type="button" className="bg-red-300 p-2 rounded-md hover:bg-red-400 transition duration-700">Clear All Todo</button>
</div>
</div>
</div>
</div>
)
}

export default App;

與 components/List/index.jsx 的內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const List = ({ todoList, setTodoList }) => {

const updateTodo = (event) => {
const { id } = event.target.dataset;
const newTodoList = todoList.map((todo) => {
if(todo.id === Number(id)) {
todo.status = !todo.status;
}
return todo;
});

setTodoList([ ...newTodoList ]);
}

const template = (todo) => {
return (
<li className="py-4" key={ todo.id }>
<label className={ todo.status ? 'line-through' : ''}>
<input type="checkbox" className="mr-2" onChange={ updateTodo } data-id={ todo.id } checked={ todo.status }/>
{ todo.name }
</label>
</li>
)
}

return ( <ul> { todoList.map((todo) => template(todo)) } </ul> )
}

export default List;

個別移動到 Vite 的 src 資料夾中即可。

當轉移完成之後你就可以在終端機輸入 npm run dev,不用一秒的時間你就可以打開瀏覽器看你的畫面,有沒有很香呢~

這邊我也附上轉移後的環境,如果你想要直接看結果的話可以直接下載下來看看。

GitHub:範例程式碼

部署到 GitHub Pages

那麼 Vite 該怎麼部署到 GitHub Pages 呢?其實非常簡單,這邊我就直接忽略 GitHub 儲存庫建立過程囉。

而部署方式其實有兩種,這邊我也一樣都介紹給大家

第一種:使用 shell script 部署

首先要改的地方是 vite.config.js,請新增一個屬性叫做 base,那裡面要寫什麼呢?就是你的 GitHub 儲存庫名稱,例如我的是 example-vite-react,所以就要寫成 base: '/example-vite-react/'

但是要注意的是,這邊的 / 不能少,不然會出現 404 的問題,除此之外我習慣在 base 增加判斷式,如果是在本地端開發的話就不要加上 /example-vite-react/,這樣就可以確保本地端開發的時候不會發生奇怪的問題。

1
2
3
4
5
6
7
8
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
base: process.env.NODE_ENV === 'production' ? '/example-vite-react/' : '/',
plugins: [react()]
})

接著建立一個叫做 deploy.sh 的檔案,並且輸入以下內容(這邊以我的儲存庫當作範例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env sh

# 發生錯誤時執行終止指令
set -e

# 打包編譯
npm run build

# 移動到打包資料夾下,若你有調整的話打包後的資料夾請務必調整
cd dist

# 部署到自定義網域
# echo 'www.example.com' > CNAME

git init
git add -A
git commit -m 'deploy'

# 部署到 https://<USERNAME>.github.io
# git push -f [email protected]:<USERNAME>/<USERNAME>.github.io.git master

# 部署到 https://<USERNAME>.github.io/<REPO>
# git push -f [email protected]:<USERNAME>/<REPO>.git master:gh-pages
# 以這個專案來講就要改成這樣以下這樣,下面是走 ssh 模式
git push -f [email protected]:hsiangfeng/example-vite-react.git master:gh-pages
# 除此之外,也可以改走 HTTPS 模式
# git push -f https://github.com/hsiangfeng/example-vite-react master:gh-pages

cd -

接著在終端機輸入 sh deploy.sh,等待它跑完就可以看到你的 GitHub Pages 囉。

而這個其實跟我以前寫的「一個指令快速部署 Vue Cli 到 GitHub Pages」非常類似,只是這邊是使用 Vite 而已。

線上範例:https://israynotarray.com/example-vite-react/

第二種:使用 gh-pages 套件部署

你想的一點都沒有錯,就是我們 CRA 章節所使用的 gh-pages 套件,這邊我們也可以使用它來部署。

第一步驟:安裝 gh-pages 套件

請在終端機輸入以下指令安裝套件

1
npm install gh-pages --save-dev

第二步驟:修改 package.json

請在 package.json 中的 scripts 屬性中新增兩個 predeploydeploy,並且輸入以下內容

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"name": "example-react-todolist",
"version": "0.1.0",
"private": true,
"dependencies": {
//...略過
},
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d dist",
//...略過
},
}

你可以發現 Vite 中是不需要 homepage 屬性的,因為 gh-pages 會自動幫你處理。

線上範例:https://israynotarray.com/example-vite-react/

第三步驟:執行指令

最後請在終端機輸入 npm run deploy,等待它跑完就可以看到你的 GitHub Pages 囉~

Vite 環境

接下來就來簡單淺談一下為什麼我們要選擇使用 Vite。

其實我們在撰寫 JavaScript 時到最後程式碼會越來越複雜,但是在早期開發時,瀏覽器還沒有支援 ESM(ES6 Modules),所以你可能會看到以下各種模組化標準

  • AMD
    • 全名為 Asynchronous Module Definition,主要依賴 requireJS
  • CMD
    • 全名為 Common Module Definition,基本上就是基於 AMD 改良而來的
  • UMD
    • 全名為 Universal Module Definition,主要是為了解決前後端共用的解決方式
  • CommonJS
    • 主流用於 Node.js,但 Node.js 13.x 之後就開始支援可以使用 ESM(ES6 Modules)

但以上這幾種模組化標準都不是這一章節要提的,所以大概知道就可以了,如果好奇的話可以去餵狗(Google)。

我們著重的重點在於 ES6 後來制定的標準 ESM(ES6 Modules),而這也是 Vite 核心基石,我們原本在前端開發上大多都必須使用 Webpack、Gulp、Rollup 或 Parcel 等打包工具,過程我們經歷各種前端工具的變化也不可否認這些工具幫我們大大改善了開發的體驗。

但是當我們專案越來越複雜,甚至是越來越大時,就會開始陸續發生以下狀況

  • 開發伺服器啟動很慢,大一點甚至高達幾秒幾分鐘
  • HMR(熱重啟、熱更新等,全名是 Hot Module Replacement) 緩慢

而目前主流開發大多都還是以 Webpack 為主,所以 Vite 官方網站就有以 Webpack 作為舉例列出一張圖片

bundle based dev server

我們可以看到上方這張圖來講 Webpack 在運作時是必須先將全部程式碼打包編譯之後再將編譯完的程式碼給 devServer 這樣子開發者才能開始開發,但如果是 Vite 呢?

Native ESM based dev server

Vite 則是將原始碼丟給了瀏覽器,完全省略了打包編譯的那一段,所以你就可以非常快速的開啟,並且只會在你需要請求特定頁面時,再去向 devServer 請求,透過 devServer 做一點簡單的處理後就直接將結果回傳給瀏覽器,所以整體上就會非常快速,也不用每次編輯或啟動就整包編譯,除此之外 Vite 的 devServer 是使用 Koa.js 唷~

那麼在開發模式下 Vite 還使用了一個東西叫做 esBuild,主要是用來幫忙處理 JavaScript/TypeScript 的部分,至於為什麼要用 esBuild 呢?簡單來講就是快!下面這張圖就是 esBuild 官方網站所提供的

esBuild

那麼為什麼 esBuild 這麼快呢?其實跟它使用的語言也有關係,esBuild 所使用的語言是 Go 語言開發的,因此在編譯上非常的快。

講了那麼多,相信你在開發時會發現 npm run build,還是會有一段打包的時間,在官方文件上其實是有提到原因的,雖然大多瀏覽器都有支援 ESM,但是考慮到效能上的因素,因此還是會建議打包比較好,這一段如果有興趣可以參考官方說法。

這時候你可能就會想說前面不是說 esBuild 非常快嗎?那為什麼打包好像有點慢?主要原因是打包時所使用的技術是 Rollup 而不是 esBuild,而這一點在官方網站也有說明到 esBuild 對於 CSS 處理等還不夠穩定的原因,因此才不採用 esBuild 來做打包,但未來不排除使用 esBuild 來做打包。

這一篇主要是簡單聊聊 Vite 的環境以及為什麼要選擇 Vite,這樣子我們就可以知道 Vite 在開發模式主要使用的技術是 ESM(ES6 Modules) + Koa.js + esBuild,而打包編譯時,則是使用到了 Rollup 唷~

那麼這一章節就差不多到這邊結束,我們明天見哩~

參考文獻

後記

本文將會同步更新到我的部落格