iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Modern Web

Fastify 101系列 第 26

[Fastify] Day26 - 前後端整合 React and Fastify-Static

  • 分享至 

  • xImage
  •  

大家好,我是 Yubin

這篇文章會介紹如何將 Fastify 作為後端,並整合前端網頁,由 Fastify App 作為前端網頁的 Host,實現 Full Stack 的專案。

前端使用 React,後端使用 Fastify 搭配 @fastify/static 為範例。


React

React 是一個 JavaScript 的函式庫,透過 React 我們可以輕鬆的設計出複雜的網頁畫面。

關於 React 的學習,可以參考官方的教學文件 或其他人的鐵人賽文章 (很多)。

我們可以透過 create-reat-app 來快速建立一個 React 專案。

Create-React-App

這邊打算把前後端的程式放在同一個專案目錄底下,用 frontend 表示前端、backend 表示後端。

mkdir my-app
cd my-app
npx create-react-app frontend --template typescript

使用 --template typescript 選擇 TypeScript 的樣板。

等專案建立好,敲入以下指令就可以看到這個樣板預設的畫面:

cd frontend
npm start

https://ithelp.ithome.com.tw/upload/images/20221011/20151148AIoGv12Jua.jpg

會自動打開預設的瀏覽器,瀏覽 localhost:30003000 是 React 開發伺服器預設使用的 Port。

Mode

這邊必須要知道的是,透過 create-react-app 產生的專案,會使用 react-scripts 做為主要的工具,其中有三個重要的 scripts 分別對應三種模式。

  • npm run start

開發模式,會把 React App 開起來,預設會聽在 localhost:3000,在這個模式下,如果有改動程式碼,畫面會自動更新,有錯誤或警告訊息也會在 Console 看到。

同時會把 NODE_ENV 環境變數設為 development


  • npm run build

生產模式,會把 React App 最佳化並打包成一些靜態檔案,出來的靜態檔案會放在 build 目錄底下。此時的 app 是可以準備部屬上線的。

打包過程中,會把 NODE_ENV 環境變數設為 production


  • npm run test

測試模式,會執行測試檔案。

測試過程中,會把 NODE_ENV 環境變數測為 test


npm run build

這邊假設我們已經把前端畫面開發完畢,敲入 npm run build

https://ithelp.ithome.com.tw/upload/images/20221011/20151148lenBRnlMva.jpg

可以看到產生出來的 build 目錄,觀察裡面可以看到 index.html 就是網頁的進入點,然後各個 React Compoment 都被最佳化並打包成許多 JavaScript, CSS 檔放在 static 目錄中。

到此,我們只需要把 build 目錄,交給一個網頁伺服器,就可以讓網站上線了。

但本篇的主題是前後端整合,我們會使用 Fastify 當作我們的前端網頁的 Host。

Fastify

在專案目錄中,建立 backend 目錄,用來放後端的程式。

cd my-app
mkdir backend
cd backend
npm init -y

這邊快速的建立一個基本的 Fastify App,還不熟 Fastify 的基本專案怎麼實作的朋友,可以參考 Fastify101: Hello World

npm i fastify
npm i -D typescript @types/node
npx tsc --init

修改 tsconfig.json

"include": ["src/**/*.ts"],
"exclude": ["node_modules"],
"compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
}

新增 src/server.ts

import fastify, { FastifyInstance } from 'fastify'

const server: FastifyInstance = fastify()

const startServer: (port: number) => FastifyInstance = (port) => {
  const listenAddress = '0.0.0.0'
  const fastifyConfig = {
    port: port,
    host: listenAddress
  }

  server.listen(fastifyConfig, (error, _) => {
    if (error) {
      console.error(error)
    }
  })

  server.get('/hello', async (request, reply) => {
    return reply.status(200).send({
      message: 'Hello World'
    })
  })

  return server
}

export { startServer }

新增程式進入點 src/index.ts

import { startServer } from './server'

const port = 8888
startServer(port)

修改 package.json 中的 scripts:

"scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
},

以上完成一個基本的 Fastify 專案架構,可以編譯並執行:

npm run build && npm run start

打開瀏覽器,瀏覽 localhost:8888/hello

https://ithelp.ithome.com.tw/upload/images/20221011/20151148kAAxYKyef6.jpg

看到如我們定義的,顯示 Hello World 回應。


一個基本的 Fastify App 已經好了,我們的前端也 build 出準備部屬的靜態檔案了,現在要讓 Fastify App 可以 serve 這些靜態檔案。

講人話,就是別人發送 Request 給伺服器想看網頁,伺服器可以回應 .html, .js, .css, .jpg 等靜態檔案出去。

這邊可以透過 Fastify 官方的 @fastify/static 來實現。

@fastify/static

@fastify/static 是一個可以快速回應靜態檔案的 Fastify Plugin。

可以透過 npm 來安裝:

npm i @fastify/static

安裝好後透過 server.register() 註冊:

import fastifyStatic from '@fastify/static'
import path from 'path'

server.register(fastifyStatic, {
    root: path.join(__dirname, '../../frontend/build'),
    prefix: '/'
})

註冊的時候可以帶入一些參數。

  • root,必要的參數,要指定要 serve 的目錄的絕對路徑。上述範例透過 path.join__dirname 來指到 frontend 專案的 build 目錄。

  • prefix,用來當 url 的前墜,預設為 /

更多參數可以參考官方的文件

接著再次編譯並把後端專案起起來:

npm run build && npm run start

打開瀏覽器,瀏覽 localhost:8888

https://ithelp.ithome.com.tw/upload/images/20221011/20151148NH65AhPydh.jpg

可以看到,原本我們的後端在 / 這個 Endpoint 沒有定義東西,應該要呈現 404 的回應,但我們透過 @fastify/static 這個 plugin 把前端網頁的靜態檔案 serve 起來,prefix 設定為 /。所以可以瀏覽到前端的畫面。

前後端整合

本文的做法,是將前端專案 build 出靜態檔案,把那些檔案交由後端的伺服器來 Serve。

注意前端專案要先 build 完,產生要部屬的靜態檔案才有畫面。

部屬方面相對單純,因為只會有後端的伺服器,別人要看網頁或 API 資源都只要跟這個伺服器作互動就好。

在前端專案的程式碼中,如果要拿取後端的 API 資源,也只要透過相對路徑的方式就可以存取到。

因為前端最後會跟後端住在一起。

假設後端有一個 API 開在 GET /hello 上。

前端的程式可以像這樣用相對路徑的方式拿到資源,而不用管後端的 hostname 是什麼:

// 以 axios 為例
const response = await axios.get('/hello')

因為最後他們是住在一起的,是同個 server 上的東西。


本文介紹了利用 @fastify/static 來實現 Full Stack 專案的前後端整合架構。

本篇以 React 專案做解釋,但這個方法不限於 React 專案,只要最後 build 出來的產物是靜態檔案的都可以用這個方式整合。

完整範例程式可以參考 GitHub


上一篇
[Fastify] Day25 - Authentication and Authorization
下一篇
[Fastify] Day27 - 網站整合 Keycloak 登入 (fastify-keycloak-adapter)
系列文
Fastify 10130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言