如何使用 Prisma Postgres 和 Cloudflare Workers 建立即時應用程式
本指南將引導您使用 Hono.js、Prisma Postgres 和 Cloudflare Workers 建立即時應用程式。在本指南結束時,您將擁有一個完整堆疊應用程式,使用者可以透過表單提交點(x
和 y
座標),在散佈圖中視覺化資料,並在新增點時即時查看更新。最終應用程式將如下所示
您將學到以下內容
- 如何使用 Prisma ORM 為 Cloudflare workers 設定 Hono.js 專案。
- 如何在 Hono.js 中使用 Prisma Postgres 的即時功能。
- 如何將專案部署到 Cloudflare。
先決條件
為了遵循本指南,請確保您具備以下條件
- Node.js 版本:相容的 Node.js 版本,Prisma 6 需要。
- 帳戶
- 建議具備 Cloudflare 部署的基本知識,以實現更順暢的實作,但非必要。
1. 設定 Cloudflare Workers 的 Hono.js
Hono.js 是一個輕量級的 Web 框架,用於建構針對邊緣環境最佳化的應用程式。從官方 Hono.js Cloudflare Workers 指南 了解更多資訊。
-
使用
create-hono
啟動器 建立一個名為realtime-app
的新 Hono.js 專案,使用cloudflare-workers
範本和npm
作為套件管理器npm create hono@latest realtime-app -- --template cloudflare-workers --pm npm
-
同意安裝先前 CLI 提示的專案相依性,然後導覽至新建立的應用程式目錄
cd ./realtime-app
2. 在您的應用程式中設定 Prisma
-
安裝 Prisma CLI 作為開發相依性
npm install prisma --save-dev
-
安裝 Prisma Accelerate 客戶端擴展,因為這是 Prisma Postgres 所需的
npm i @prisma/extension-accelerate
-
安裝 Prisma Pulse 客戶端擴展 以取得即時資料庫更新
npm i @prisma/extension-pulse
-
在您的應用程式中初始化 Prisma
npx prisma init
這將建立
- 一個包含
schema.prisma
的prisma
資料夾,您將在其中定義資料庫結構描述。 - 專案根目錄中的一個
.env
檔案,用於儲存環境變數。注意您將不會使用
.env
檔案,因為它們與 Cloudflare Workers 不相容。您稍後將刪除此檔案。
3. 建立 Prisma Postgres 執行個體並啟用即時功能
為了儲存應用程式的資料,您將使用 Prisma Data Platform 建立 Prisma Postgres 資料庫執行個體。
請按照以下步驟建立您的 Prisma Postgres 資料庫
- 登入並開啟主控台。
- 在您選擇的工作區中,按一下 New project(新增專案)按鈕。
- 在 Name(名稱)欄位中輸入專案名稱,例如 hello-ppg。
- 在 Prisma Postgres 區段中,按一下 Get started(開始使用)按鈕。
- 在 Region(區域)下拉式選單中,選取最靠近您目前位置的區域,例如 US East (N. Virginia)(美國東部(維吉尼亞北部))。
- 按一下 Create project(建立專案)按鈕。
此時,您將被重新導向至 Database(資料庫)頁面,您需要在該頁面等待幾秒鐘,直到資料庫的狀態從 PROVISIONING
變更為 CONNECTED
。
一旦出現綠色的 CONNECTED
標籤,您的資料庫即可使用!
您還需要在主控台中啟用 Prisma Postgres 的即時功能
- 在側邊導覽列中選取 Pulse 標籤。
- 找到並按一下 Enable Pulse(啟用 Pulse)按鈕。
- 在 Add Pulse to your application(將 Pulse 新增至您的應用程式)區段中,按一下 Generate API key(產生 API 金鑰)按鈕。
- 安全地儲存
PULSE_API_KEY
環境變數,因為本指南需要用到它。
然後,在 Set up database access(設定資料庫存取權限)區段中找到您的資料庫憑證,複製 DATABASE_URL
環境變數,並與 PULSE_APLI_KEY
一起安全地儲存。
DATABASE_URL=<your-database-url>
PULSE_API_KEY=<your-pulse-api-key>
在後續步驟中將需要這些環境變數。
3.1. 設定開發環境變數
-
在您的專案根目錄中,建立一個
.dev.vars
檔案以儲存環境變數.dev.varsDATABASE_URL=<your-database-url>
PULSE_API_KEY=<your-pulse-api-key> -
刪除由 Prisma 初始化建立的
.env
檔案,因為.env
與 Cloudflare Workers 不相容。
3.2. 更新您的 Prisma 結構描述
-
開啟
prisma
資料夾中的schema.prisma
檔案。 -
新增以下模型以定義資料庫的結構
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Points {
id Int @id @default(autoincrement())
x Int
y Int
}
此模型定義了一個 Points
表格,其中包含欄位 id
、x
和 y
。
3.3. 套用資料庫結構描述變更
為了使用結構描述變更更新您的資料庫,您將建立並執行移轉。
-
安裝
dotenv-cli
套件 以從.dev.vars
載入環境變數npm i -D dotenv-cli
-
將移轉腳本新增至
package.json
的scripts
區段"scripts": {
"migrate": "dotenv -e .dev.vars -- npx prisma migrate dev"
// Other scripts created by Hono
} -
執行移轉腳本以將變更套用至資料庫
npm run migrate
-
出現提示時,為移轉提供名稱(例如,
init
)。 -
使用
--no-engine
旗標產生PrismaClient
,以便為邊緣執行階段產生用戶端npx prisma generate --no-engine
完成以上步驟後,您的 Prisma ORM 已完全設定並連接到您的 Postgres 資料庫。
4. 開發應用程式
現在,您將開發一個即時應用程式。該應用程式將讓使用者透過簡單的表單提交點(x
和 y
座標),並在散佈圖中顯示它們,每當新增一個新點時,散佈圖都會自動更新。
4.1. 清空現有的 src/index.ts
檔案
從 src/index.ts
檔案中移除所有內容,以從頭開始。對於以下每個步驟,將新的程式碼區塊附加到 index.ts
的末尾。
4.2. 設定相依性和環境綁定
新增所需的匯入並定義 環境變數綁定,以在您的應用程式中使用 DATABASE_URL
和 PULSE_API_KEY
import { PrismaClient } from "@prisma/client/edge";
import { withAccelerate } from "@prisma/extension-accelerate";
import { withPulse } from "@prisma/extension-pulse/workerd";
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/cloudflare-workers";
import { requestId } from 'hono/request-id';
// Define environment bindings
type Bindings = {
DATABASE_URL: string;
PULSE_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.use('*', requestId());
4.3. 建立一個輔助方法以在應用程式中使用 PrismaClient
建立一個輔助函式以使用 Prisma Accelerate 和 Pulse 用戶端擴展初始化 PrismaClient
const createPrismaClient = (databaseUrl: string, pulseApiKey: string) => {
return new PrismaClient({
datasourceUrl: databaseUrl,
})
.$extends(withAccelerate())
.$extends(
withPulse({
apiKey: pulseApiKey,
})
);
};
4.4. 建立路由以建立 WebSocket 連線
當新點新增至資料庫時,此路由會即時串流更新
app.get(
"/ws",
upgradeWebSocket(async (c) => {
const prisma = createPrismaClient(c.env.DATABASE_URL, c.env.PULSE_API_KEY);
let listeningToRealtimeStream = false;
return {
onMessage(event, ws) {
if (!listeningToRealtimeStream) {
c.executionCtx.waitUntil(
(async () => {
listeningToRealtimeStream = true;
const pointStream = await prisma.points.stream({
name: `points-stream-${c.get('requestId')}`,
create: {},
});
for await (const event of pointStream) {
ws.send(JSON.stringify({ x: event.created.x, y: event.created.y }));
}
})()
);
}
},
onClose: () => console.log("WebSocket connection closed."),
};
})
);
4.5. 建立 POST
路由,讓您可以將 Points
儲存到資料庫中
此路由驗證使用者輸入並將新點儲存到資料庫中
app.post("/", async (c) => {
const { x, y } = await c.req.json();
if (typeof x !== "number" || typeof y !== "number") {
return c.text("Invalid input: x and y must be numbers.", 400);
}
const prisma = createPrismaClient(c.env.DATABASE_URL, c.env.PULSE_API_KEY);
const newPoint = await prisma.points.create({ data: { x, y } });
return c.json({ point: newPoint });
});
4.6. 建立一個 GET
路由,用於提供 HTML 頁面
此路由提供包含表單和散佈圖的 HTML 頁面。它還建立與 WebSocket 路由的連線,並即時接收和反映來自 Prisma Postgres 的事件
app.get("/", async (c) => {
const prisma = createPrismaClient(c.env.DATABASE_URL, c.env.PULSE_API_KEY);
const dataPoints = await prisma.points.findMany({
take: 100,
orderBy: { id: "desc" },
select: { x: true, y: true },
}) || [];
return c.html(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Realtime Line Chart</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
html, body {
margin: 0;
padding: 0;
font-family: sans-serif;
height: 100%;
}
.form-container { margin: 1rem; text-align: center; }
.chart-container { display: flex; justify-content: center; min-height: 70vh; }
canvas { max-width: 500px; height: 100%; }
</style>
</head>
<body>
<div class="form-container">
<form id="pointForm">
<input type="number" name="x" placeholder="Enter X" required />
<input type="number" name="y" placeholder="Enter Y" required />
<button type="submit">Add Point</button>
</form>
</div>
<div class="chart-container"><canvas id="myChart"></canvas></div>
<script>
const dataPoints = ${JSON.stringify(dataPoints).replace(/`/g, '\\`')};
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [
{
label: \`Points data\`,
data: dataPoints,
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.5)',
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: { type: 'linear', position: 'bottom', title: { display: true, text: 'X Axis' } },
y: { beginAtZero: true, title: { display: true, text: 'Y Axis' } },
},
},
});
const form = document.getElementById('pointForm');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const x = parseFloat(formData.get('x'));
const y = parseFloat(formData.get('y'));
if (isNaN(x) || isNaN(y)) return alert('Invalid input');
try {
const res = await fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ x, y }),
});
if (!res.ok) throw new Error('API error');
form.reset();
} catch (err) {
alert('Failed to add point');
}
});
const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const wsUrl = wsProtocol.concat("://").concat(window.location.host).concat("/ws");
const ws = new WebSocket(wsUrl);
ws.onopen = () => {
ws.send('Connect to WebSocket server');
};
ws.onmessage = (event) => {
const point = JSON.parse(event.data);
myChart.data.datasets[0].data.push(point);
myChart.update();
};
ws.onerror = () => alert('WebSocket error');
ws.onclose = () => alert('WebSocket closed');
</script>
</body>
</html>
`);
});
export default app;
4.7. 啟動伺服器並測試您的應用程式
執行開發伺服器
npm run dev
造訪 https://127.0.0.1:8787
以查看您的應用程式運作情況。
您會找到一個表單,您可以在其中輸入 x
和 y
值。每次您提交表單時,散佈圖都應即時更新以反映新資料
您也可以從任何地方將點直接新增到您的 Prisma Postgres 資料庫。例如,使用 Prisma Studio for Prisma Postgres 輸入 x
和 y
點,散佈圖圖表將立即更新。
5. 將應用程式部署到 Cloudflare
現在您將把您的即時應用程式部署到 Cloudflare Workers。這包括上傳您的應用程式程式碼並安全地設定您的環境變數。
5.1. 使用 Wrangler 部署應用程式
-
使用以下命令將您的專案部署到 Cloudflare Workers
npm run deploy
wrangler
CLI 將會捆綁並上傳您的應用程式。 -
如果您尚未登入,
wrangler
CLI 將會開啟一個瀏覽器視窗,提示您登入 Cloudflare 儀表板。注意如果您屬於多個帳戶,請選取您要部署專案的帳戶。
-
部署完成後,您將看到類似以下的輸出
> deploy
> wrangler deploy --minify
⛅️ wrangler 3.101.0
Total Upload: 243.40 KiB / gzip: 83.31 KiB
Worker Startup Time: 20 ms
Uploaded realtime-app (9.80 sec)
Deployed realtime-app triggers (1.60 sec)
https://realtime-app.workers.dev
Current Version ID: {VERSION_ID}請注意傳回的 URL,例如
https://realtime-app.workers.dev
。這是您的線上應用程式 URL。
5.2. 為應用程式設定機密資訊
您的應用程式需要 DATABASE_URL
和 PULSE_API_KEY
環境變數才能運作。這些機密資訊必須安全地上傳到 Cloudflare。
-
使用
npx wrangler secret put
命令 上傳DATABASE_URL
npx wrangler secret put DATABASE_URL
出現提示時,貼上
DATABASE_URL
值。 -
同樣地,上傳
PULSE_API_KEY
npx wrangler secret put PULSE_API_KEY
出現提示時,貼上
PULSE_API_KEY
值。
5.3. 重新部署應用程式
設定機密資訊後,重新部署您的應用程式,以確保它可以存取環境變數
npm run deploy
5.4. 驗證部署
造訪部署輸出中提供的線上 URL,例如 https://realtime-app.workers.dev
。
您的應用程式現在應該已完全正常運作
- 提交點的表單應可運作。
- 散佈圖應顯示資料並即時更新。
如果您遇到任何問題,請確保機密資訊已正確新增,並檢查部署日誌中是否有錯誤。
後續步驟
恭喜您使用 Prisma Postgres 和 Cloudflare Workers 建立並部署了您的即時應用程式。
您的應用程式現在已上線,並使用邊緣執行階段中的 WebSocket 支援處理即時更新。為了進一步增強它
- 使用 Prisma Accelerate 新增 快取 以提升效能。
- 探索 Prisma Postgres 文件。