deno.com
本頁內容

使用 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 命令包含 descriptiondependencies

太棒了!接下來,讓我們設定我們的 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 不同的關鍵之處需要注意

  1. 我們使用 SolidJS 特有的基本元素
    • createSignal 而不是 useState
    • createEffect 而不是 useEffect
    • For 元件而不是 map
    • A 元件而不是 Link
  2. SolidJS 元件使用細粒度的反應性,因此我們將信號呼叫為函式,例如 dinosaur() 而不是僅僅 dinosaur
  3. 路由由 @solidjs/router 而不是 react-router-dom 處理
  4. 元件匯入使用 Solid 的 lazy 進行程式碼分割

Index 頁面使用 SolidJS 的 createSignal 來管理恐龍列表,並使用 onMount 在元件載入時提取資料。我們使用 For 元件,這是 SolidJS 呈現列表的有效方式,而不是使用 JavaScript 的 map 函式。來自 @solidjs/routerA 元件建立用戶端導覽連結到個別恐龍頁面,防止完整的頁面重新載入。

現在是 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 檔案,它將同時作為元件提供 IndexDinosaur 頁面。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 應用程式了!以下是一些您可以增強恐龍應用程式的方法

SolidJS 獨特的反應式基本元素、真正的 DOM 調和以及 Deno 的現代執行時期,為 Web 開發提供了非常有效率的基礎。由於沒有 Virtual DOM 的開銷,並且僅在需要時進行細微的更新,您的應用程式可以實現最佳效能,同時保持乾淨、可讀的程式碼。

您找到需要的資訊了嗎?

隱私權政策