
專案設定 - Clean Architecture in TypeScript
這一系列會預設在 Cloudflare 相容的環境下運行,在前端開發的部分會以 Vite 搭配 Hono 來使用,這幾個工具有很不錯的相容性,很適合在這次的情境中使用。
初始化專案
首先,我們使用 Cloudflare 的 Wrangler 來初始化專案,建立一個以 Hello World 為樣板,選擇「Worker only」並且使用 TypeScript 的新專案。
1npx wrangler init
大部分樣板的初始設定不會差異太大,但我們使用比較簡單的 Worker only 會比較容易繼續後續的處理。
接下來我們要把 Vite、Hono、Hono 的 Vite Dev Server 加入到專案裡面。
1npm install -D vite @hono/vite-dev-server
2npm install hono
接下來,先暫時將 src/index.ts
替換為以下內容,確保 Hono 運作正常。
1import { Hono } from 'hono';
2
3const app = new Hono();
4
5app.get('/', (c) => c.text('Hello World!'));
6
7export default {
8 fetch: app.fetch,
9} satisfies ExportedHandler<Env>;
因為 Worker only 樣板預設會對 Hello World!
的回傳進行測試,可以運行 npm run test
快速驗證修改。
接下來加入 vite.config.mts
設定使用 Vite 運行開發環境。
1import devServer from "@hono/vite-dev-server";
2import cloudflareAdapter from "@hono/vite-dev-server/cloudflare";
3import { defineConfig, Plugin } from "vite";
4
5export default defineConfig(() => {
6 return {
7 plugins: [
8 devServer({
9 entry: "./src/index.ts",
10 adapter: cloudflareAdapter,
11 }),
12 ] as Plugin[],
13 };
14});
Hono 已經幫我們準備好對應 Cloudflare 環境的 Adapter 因此會需要在 Vite 的 devServer
中額外設定,指定到我們要的檔案上。
最後更新 package.ts
將原本的 wrangler dev
替換為 vite
就可以用 npm run dev
看到使用 Vite 的版本。
前端設定
我們要使用 Hono 同時來開發前端跟後端,這也是採用 Vite 的理由之一,因此我們還需要更近一步做設定,讓前後端都能夠被處理。
加入新的套件,用於處理前端的建置以及使用 TailwindCSS 作為本次前端的外觀設計。
1npm install -D @hono/vite-build
2npm install tailwindcss @tailwindcss/vite
接下來修改 vite.config.mts
為以下的狀態,根據 Hono 的文件,我們需要區分當下建置的是前端還是後端,並且給予不同的設定,不過在開發模式下只需要後端的即可,因此預設回傳後端的設定。
1import build from "@hono/vite-build/cloudflare-workers";
2import devServer from "@hono/vite-dev-server";
3import cloudflareAdapter from "@hono/vite-dev-server/cloudflare";
4import tailwindcss from "@tailwindcss/vite";
5import { defineConfig, Plugin } from "vite";
6
7export default defineConfig(({ mode }) => {
8 if (mode == "client") {
9 return {
10 build: {
11 rollupOptions: {
12 input: ["./src/client.tsx"],
13 output: {
14 entryFileNames: "public/app.js",
15 chunkFileNames: "public/assets/[name]-[hash].js",
16 assetFileNames: "public/assets/[name].[ext]",
17 },
18 },
19 emptyOutDir: false,
20 copyPublicDir: false,
21 },
22 plugins: [tailwindcss()],
23 };
24 }
25
26 return {
27 plugins: [
28 devServer({
29 entry: "./src/index.tsx",
30 adapter: cloudflareAdapter,
31 }),
32 build({
33 entry: "./src/index.tsx",
34 }),
35 tailwindcss(),
36 ] as Plugin[]
37 };
38});
接著我們要修改 tsconfig.json
加入對應的設定,調整以下參數。
1{
2 "compilerOptions": {
3 "jsx": "react-jsx",
4 "jsxImportSource": "hono/jsx",
5 }
6}
將 JSX 的來源指定為 hono/jsx
用來代替原生的 React 元件。
1{
2 "compilerOptions": {
3 "types": [
4 "@cloudflare/workers-types/2023-07-01", "vite/client"
5 ],
6 }
7}
將 Vite 的型別定義加入到 types
中,新版的 Cloudflare Worker 可以不再依賴 workers-types
這邊可以考慮將其移除,短時間內不影響開發。
1{
2 "include": ["worker-configuration.d.ts", "src/**/*.ts", "src/**/*.tsx"]
3}
原本只會將 .ts
包含進來,因為使用了 JSX 所以需要把 .tsx
檔案也一起涵蓋進去。
接下來將原本的 src/index.ts
改為 src/index.tsx
加入空白的前端頁面。
1import { Hono } from 'hono';
2
3const app = new Hono();
4
5app.get("/", (c) =>
6 c.html(
7 <html lang="zh-TW">
8 <head>
9 <title>Clean Architecture in TypeScript</title>
10 <meta charSet="utf-8" />
11 <meta content="width=device-width, initial-scale=1" name="viewport" />
12 {import.meta.env.PROD ? (
13 <script type="module" src="/app.js" />
14 ) : (
15 <script type="module" src="/src/client.tsx" />
16 )}
17 </head>
18 <body>
19 <div id="root" />
20 </body>
21 </html>,
22 ),
23);
24
25export default {
26 fetch: app.fetch,
27} satisfies ExportedHandler<Env>;
上述是 Hono 比較特殊的用法,我們可以直接在後端使用 JSX 語法撰寫 HTML 且能夠正常運作,如果專案比較單純的話,是一個不錯的方案。
加入新的 src/client.tsx
放入簡單的 console.log("Hello World")
我們就可以透過 npm run dev
看到畫面變成空白,並且在開發者工具的 Console 可以看到 Hello World 的訊息。
最後,更新 wrangler.jsonc
將以下這行註解取消,新專案還需要注意前一個設定尾端是否有 ,
1{
2 "assets": { "directory": "./public/", "binding": "ASSETS" },
3}
這樣一來我們在開發跟部署就能夠都使用 Hono 來進行,其他像是 vite-tsconfig-paths
、Pritter 等套件,則可以看需求安裝。
依賴注入
因為我們選用 tsyring
作為依賴注入框架的關係,還需要額外啟用一些 TypeScript 的特性才可以使用。
先安裝依賴注入相關的套件。
1npm install tsyringe reflect-metadata
在 tsconfig.json
啟用實驗性的功能
1{
2 "compilerOptions": {
3 "experimentalDecorators": true,
4 "emitDecoratorMetadata": true
5 }
6}
最後在 src/index.tsx
第一行加入 Reflect Metadata 的引用。
1import "reflect-metadata";
2
3// ...
這個引用必須放在第一行,才不會在後續編譯後因為找不到引用的設定而無法正常運行專案。到此為止,我們將整個專案必要的設定都處理完畢,可以開始進入開發階段。
上述的專案設定大多是可以轉換為樣板的,如果認為經常會採用這樣的做法,以使用樣板機制為前提,撰寫成 AI 提示(Prompt)反而會降低成功率,AI 比較適合在針對細部微調的情境採用。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。