使用 Deno 建構 SolidJS 應用程式
SolidJS 是一個宣告式的 JavaScript 函式庫,用於建立使用者介面,強調細粒度的反應性和最小的開銷。當與 Deno 的現代執行時期環境結合時,您將獲得一個強大、高效能的堆疊,用於建構 Web 應用程式。在本教學中,我們將建構一個簡單的恐龍目錄應用程式,示範這兩項技術的關鍵功能。
我們將逐步介紹如何使用 Deno 建構一個簡單的 SolidJS 應用程式
您可以直接跳到原始碼,或繼續閱讀以下內容!
使用 Vite 建立 SolidJS 應用程式骨架 跳到標題
讓我們使用 Vite 設定我們的 SolidJS 應用程式,Vite 是一個現代化的建構工具,提供絕佳的開發體驗,並具有熱模組替換和最佳化建構等功能。
deno init --npm vite@latest solid-deno --template solid-ts
我們的後端將由 Hono 提供支援,我們可以透過 JSR 安裝 Hono。讓我們也新增 solidjs/router
,用於用戶端路由和恐龍目錄頁面之間的導覽。
deno add jsr:@hono/hono npm:@solidjs/router
deno add
以及將 Deno 用作套件管理器。
我們還需要更新我們的 deno.json
,以包含一些任務和 compilerOptions
來執行我們的應用程式
{
"tasks": {
"dev": "deno task dev:api & deno task dev:vite",
"dev:api": "deno run --allow-env --allow-net --allow-read api/main.ts",
"dev:vite": "deno run -A npm:vite",
"build": "deno run -A npm:vite build",
"serve": {
"command": "deno task dev:api",
"description": "Run the build, and then start the API server",
"dependencies": ["deno task build"]
}
},
"imports": {
"@hono/hono": "jsr:@hono/hono@^4.6.12",
"@solidjs/router": "npm:@solidjs/router@^0.14.10"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "solid-js",
"lib": ["DOM", "DOM.Iterable", "ESNext"]
}
}
tasks
寫成物件。這裡我們的 serve
命令包含 description
和 dependencies
。太棒了!接下來,讓我們設定我們的 API 後端。
設定我們的 Hono 後端 跳到標題
在我們的主目錄中,我們將設定一個 api/
目錄並建立兩個檔案。首先是我們的恐龍資料檔案,api/data.json
// api/data.json
[
{
"name": "Aardonyx",
"description": "An early stage in the evolution of sauropods."
},
{
"name": "Abelisaurus",
"description": "\"Abel's lizard\" has been reconstructed from a single skull."
},
{
"name": "Abrictosaurus",
"description": "An early relative of Heterodontosaurus."
},
...
]
這將是我們資料的來源。在完整的應用程式中,這些資料將來自資料庫。
⚠️️ 在本教學中,我們硬式編碼資料。但是您可以連線到各種資料庫,甚至可以將ORM(例如 Prisma)與 Deno 搭配使用。
其次,我們需要我們的 Hono 伺服器,api/main.ts
// api/main.ts
import { Hono } from "@hono/hono";
import data from "./data.json" with { type: "json" };
const app = new Hono();
app.get("/", (c) => {
return c.text("Welcome to the dinosaur API!");
});
app.get("/api/dinosaurs", (c) => {
return c.json(data);
});
app.get("/api/dinosaurs/:dinosaur", (c) => {
if (!c.req.param("dinosaur")) {
return c.text("No dinosaur name provided.");
}
const dinosaur = data.find((item) =>
item.name.toLowerCase() === c.req.param("dinosaur").toLowerCase()
);
console.log(dinosaur);
if (dinosaur) {
return c.json(dinosaur);
} else {
return c.notFound();
}
});
Deno.serve(app.fetch);
此 Hono 伺服器提供兩個 API 端點
GET /api/dinosaurs
以取得所有恐龍,以及GET /api/dinosaurs/:dinosaur
以依名稱取得特定恐龍
當我們執行 deno task dev
時,此伺服器將在 localhost:8000
上啟動。
最後,在我們開始建構前端之前,讓我們使用以下內容更新我們的 vite.config.ts
檔案,特別是 server.proxy
,它會告知我們的 SolidJS 前端 API 端點的位置。
// vite.config.ts
import { defineConfig } from "vite";
import solid from "vite-plugin-solid";
export default defineConfig({
plugins: [solid()],
server: {
proxy: {
"/api": {
target: "https://127.0.0.1:8000",
changeOrigin: true,
},
},
},
});
建立我們的 SolidJS 前端 跳到標題
在我們開始建構前端元件之前,讓我們先在 src/types.ts
中定義 Dino
型別
// src/types.ts
export type Dino = {
name: string;
description: string;
};
Dino
型別介面可確保我們應用程式中的型別安全,定義恐龍資料的形狀並啟用 TypeScript 的靜態型別檢查。
接下來,讓我們設定前端以接收該資料。我們將有兩個頁面
Index.tsx
Dinosaur.tsx
以下是 src/pages/Index.tsx
頁面的程式碼
// src/pages/Index.tsx
import { createSignal, For, onMount } from "solid-js";
import { A } from "@solidjs/router";
import type { Dino } from "../types.ts";
export default function Index() {
const [dinosaurs, setDinosaurs] = createSignal<Dino[]>([]);
onMount(async () => {
try {
const response = await fetch("/api/dinosaurs");
const allDinosaurs = (await response.json()) as Dino[];
setDinosaurs(allDinosaurs);
console.log("Fetched dinosaurs:", allDinosaurs);
} catch (error) {
console.error("Failed to fetch dinosaurs:", error);
}
});
return (
<main>
<h1>Welcome to the Dinosaur app</h1>
<p>Click on a dinosaur below to learn more.</p>
<For each={dinosaurs()}>
{(dinosaur) => (
<A href={`/${dinosaur.name.toLowerCase()}`} class="dinosaur">
{dinosaur.name}
</A>
)}
</For>
</main>
);
}
使用 SolidJS 時,有幾個與 React 不同的關鍵之處需要注意
- 我們使用 SolidJS 特有的基本元素
createSignal
而不是useState
createEffect
而不是useEffect
For
元件而不是map
A
元件而不是Link
- SolidJS 元件使用細粒度的反應性,因此我們將信號呼叫為函式,例如
dinosaur()
而不是僅僅dinosaur
- 路由由
@solidjs/router
而不是react-router-dom
處理 - 元件匯入使用 Solid 的
lazy
進行程式碼分割
Index
頁面使用 SolidJS 的 createSignal
來管理恐龍列表,並使用 onMount
在元件載入時提取資料。我們使用 For
元件,這是 SolidJS 呈現列表的有效方式,而不是使用 JavaScript 的 map 函式。來自 @solidjs/router
的 A
元件建立用戶端導覽連結到個別恐龍頁面,防止完整的頁面重新載入。
現在是 src/pages/Dinosaur.tsx
的個別恐龍資料頁面
// src/pages/Dinosaur.tsx
import { createSignal, onMount } from "solid-js";
import { A, useParams } from "@solidjs/router";
import type { Dino } from "../types.ts";
export default function Dinosaur() {
const params = useParams();
const [dinosaur, setDinosaur] = createSignal<Dino>({
name: "",
description: "",
});
onMount(async () => {
const resp = await fetch(`/api/dinosaurs/${params.selectedDinosaur}`);
const dino = (await resp.json()) as Dino;
setDinosaur(dino);
console.log("Dinosaur", dino);
});
return (
<div>
<h1>{dinosaur().name}</h1>
<p>{dinosaur().description}</p>
<A href="/">Back to all dinosaurs</A>
</div>
);
}
Dinosaur
頁面透過使用 useParams
存取 URL 參數,示範 SolidJS 的動態路由方法。它遵循與 Index
頁面類似的模式,使用 createSignal
進行狀態管理,並使用 onMount
進行資料提取,但專注於單一恐龍的詳細資訊。此 Dinosaur
元件也示範如何在範本中存取訊號值,方法是將它們呼叫為函式(例如,dinosaur().name
),這與 React 的狀態管理方式有很大的不同。
最後,為了將所有內容結合在一起,我們將更新 App.tsx
檔案,它將同時作為元件提供 Index
和 Dinosaur
頁面。App
元件使用 @solidjs/router
設定我們的路由設定,定義兩個主要路由:用於恐龍列表的索引路由,以及用於個別恐龍頁面的動態路由。路由路徑中的 :selectedDinosaur
參數建立一個動態區段,該區段與 URL 中的任何恐龍名稱匹配。
// src/App.tsx
import { Route, Router } from "@solidjs/router";
import Index from "./pages/Index.tsx";
import Dinosaur from "./pages/Dinosaur.tsx";
import "./App.css";
const App = () => {
return (
<Router>
<Route path="/" component={Index} />
<Route path="/:selectedDinosaur" component={Dinosaur} />
</Router>
);
};
export default App;
最後,此 App
元件將從我們的主索引中呼叫
// src/index.tsx
import { render } from "solid-js/web";
import App from "./App.tsx";
import "./index.css";
const wrapper = document.getElementById("root");
if (!wrapper) {
throw new Error("Wrapper div not found");
}
render(() => <App />, wrapper);
我們應用程式的進入點使用 SolidJS 的 render
函式將 App 元件掛載到 DOM。它包含安全檢查,以確保根元素在嘗試呈現之前存在,從而在初始化期間提供更好的錯誤處理。
現在,讓我們執行 deno task dev
以同時啟動前端和後端
下一步 跳到標題
🦕 現在您可以使用 Deno 建構和執行 SolidJS 應用程式了!以下是一些您可以增強恐龍應用程式的方法
- 新增持久性資料儲存區使用資料庫(例如 Postgres 或 MongoDB)和 ORM(例如 Drizzle 或 Prisma)
- 使用 SolidJS 的
createContext
實作全域狀態,以在元件之間共用資料 - 使用
createResource
的載入屬性新增載入狀態 - 使用
lazy
匯入實作基於路由的程式碼分割 - 使用
Index
元件以獲得更有效率的列表呈現 - 將您的應用程式部署到 AWS、Digital Ocean 或 Google Cloud Run
SolidJS 獨特的反應式基本元素、真正的 DOM 調和以及 Deno 的現代執行時期,為 Web 開發提供了非常有效率的基礎。由於沒有 Virtual DOM 的開銷,並且僅在需要時進行細微的更新,您的應用程式可以實現最佳效能,同時保持乾淨、可讀的程式碼。