Node.js Web 框架-我們從哪裡開始?有這麼多的選擇,為您的專案選擇合適的一個可能會讓人感到不知所措。
在這篇文章中,我將帶您了解 Node.js 生態系統中最熱門的框架,詳細介紹每個框架的優點、缺點和最佳用例。
無論您追求的是速度、可擴展性還是簡單性,希望我們都能涵蓋所有內容,因此到最後,您將確切地知道哪個框架適合您。
我們將要關注的框架是: Nest 、 Elysia 、 Encore.ts和Hono 。
影片版本:
{% 嵌入 https://www.youtube.com/watch?v=SEXpJbmab08 %}
從最輕量級到功能最豐富的範圍,我將框架定位如下:
這並不意味著輕量級不好,它只是取決於您的專案的需求。 Hono的輕量級本質實際上是其賣點之一,其大小不到 14KB,非常適合部署到 Cloudflare Workers。
另一方面, Encore.ts具有許多內建功能,例如開箱即用的自動追蹤和本地基礎架構。
讓我們來看看每個框架,我們將從 Encore.ts 開始
一個開源框架,旨在更輕鬆地使用 TypeScript 建立健全且類型安全的後端。該框架有許多內建工具,可以讓您的開發體驗更加流暢,效能更佳,在本次比較中,它是所有框架中速度更快的。
<
表>
<td><a href="https://encore.dev/docs/ts/primitives/apis" class="link-brandient">Type-safe API schemas</a></td>
<td><a href="https://encore.dev/docs/ts/develop/cors" class="link-brandient">CORS handling</a></td>
<td><a href="https://encore.dev/docs/ts/develop/logging" class="link-brandient">Structured logging</a></td>
<td><a href="https://encore.dev/docs/ts/develop/auth" class="link-brandient">Authentication</a></td>
<td><a href="https://encore.dev/docs/ts/primitives/pubsub" class="link-brandient">Pub/Sub integrations</a></td>
<td><a href="https://encore.dev/docs/ts/primitives/secrets" class="link-brandient">Secrets management</a></td>
<td><a href="https://encore.dev/docs/deploy/infra" class="link-brandient">Infrastructure integrations</a></td>
<td><a href="https://encore.dev/docs/ts/primitives/databases" class="link-brandient">Database integrations</a></td>
<td><a href="https://encore.dev/docs/observability/encore-flow" class="link-brandient">Architecture Diagrams</a>
</td>
<td><a href="https://encore.dev/docs/observability/dev-dash" class="link-brandient">Local Development Dashboard</a>
</td>
<td><a href="https://encore.dev/docs/develop/api-docs" class="link-brandient">Service Catalog</a></td>
<td><a href="https://encore.dev/docs/ts" class="link-brandient">TypeScript native</a></td>
<td><a href="https://encore.dev/docs/ts/develop/debug" class="link-brandient">Debugging</a></td>
<td><a href="https://encore.dev/docs/ts/develop/errors" class="link-brandient">Error handling</a></td>
<td><a href="https://encore.dev/blog/event-loops" class="link-brandient">Multithreading</a></td>
<td><a href="https://encore.dev/blog/event-loops" class="link-brandient">Request validation</a></td>
<td><a href="https://encore.dev/docs/observability/tracing" class="link-brandient">Tracing</a></td>
<td><a href="https://encore.dev/docs/develop/client-generation" class="link-brandient">API Client generation</a>
</td>
<td><a href="https://encore.dev/docs/deploy/infra" class="link-brandient">Automatic local infrastructure</a></td>
<td><a href="https://encore.dev/docs/ts/develop/testing" class="link-brandient">Automated testing</a></td>
Encore 具有內建的請求驗證。您在常規 TypeScript 中定義的請求和回應類型用於在編譯和執行時驗證請求。與其他框架不同的是,實際的驗證是在 Rust 中完成的,而不是在 JavaScript 中完成。這使得驗證非常快,稍後會詳細介紹。
import {api, Header, Query} from "encore.dev/api";
enum EnumType {
FOO = "foo",
BAR = "bar",
}
// Encore.ts automatically validates the request schema
// and returns and error if the request does not match.
interface RequestSchema {
foo: Header<"x-foo">;
name?: Query<string>;
someKey?: string;
someOtherKey?: number;
requiredKey: number[];
nullableKey?: number | null;
multipleTypesKey?: boolean | number;
enumKey?: EnumType;
}
// Validate a request
export const schema = api(
{expose: true, method: "POST", path: "/validate"},
(data: RequestSchema): { message: string } => {
console.log(data);
return {message: "Validation succeeded"};
},
);
Encore 讓建立和呼叫服務變得容易。從程式碼的角度來看,服務看起來就像是儲存庫中的另一個資料夾。呼叫服務中的端點時,就像呼叫常規函數一樣。但最酷的部分是,在幕後,這些函數呼叫會轉換為實際的 HTTP 呼叫。部署時,您甚至可以選擇將服務部署到單獨的執行個體(例如 Kubernetes 叢集中),同時仍將所有服務程式碼放在同一個儲存庫中。
導入服務並像常規函數一樣呼叫其 API 端點
import { api } from "encore.dev/api";
import { hello } from "~encore/clients"; // import 'hello' service
export const myOtherAPI = api({}, async (): Promise<void> => {
// all the ping endpoint using a function call
const resp = await hello.ping({ name: "World" });
console.log(resp.message); // "Hello World!"
});
使用 Encore.ts,您可以將基礎架構集成為應用程式程式碼中的類型安全性物件。建立資料庫或 Pub/Sub 主題只需要幾行應用程式程式碼。 Encore.ts 將您的應用程式建置為 Docker 映像,您只需在部署時提供執行時間配置即可。
一行程式碼建立 PostgreSQL 資料庫
import { SQLDatabase } from "encore.dev/storage/sqldb";
const db = new SQLDatabase("userdb", {migrations: "./migrations"});
// ... use db.query to query the database.
建立 Pub/Sub 主題和訂閱
import { Topic } from "encore.dev/pubsub";
export interface User { /* fields ... */ }
const signups = new Topic<User>("signup", {
deliveryGuarantee: "at-least-once",
});
await signups.publish({ ... });
Encore 還配備了一個內建的開發儀表板。當您啟動 Encore 應用程式時,開發儀表板可在連接埠localhost:9400上使用。從這裡您可以呼叫端點,有點像 Postman。對應用程式的每次呼叫都會產生一個跟踪,您可以檢查該跟踪以查看 API 請求、資料庫呼叫和 Pub/Sub 訊息。本地開發儀表板還包括自動 API 文件和始終最新的系統架構圖。
本地發展儀表板
{% 嵌入 https://www.youtube.com/watch?v=Da\_jHj6bLac %}
值得一提的是,儘管 Encore 具有許多功能,但它的npm 依賴項為 0 。
Hono是和田佑介的創作。他在 2021 年啟動了這個專案,因為當時沒有在Cloudflare Workers上運作良好的 Node.js 框架。從那時起,Hono 增加了對許多其他執行時(如 Node.js、Bun 和 Deno)的支援。
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono!'))
export default app
Hono 非常小, hono/tiny
預設不到 13kB,這使得它非常適合部署到 Cloudflare Workers。 Hono 還具有0 個 NPM 依賴項,這確實令人印象深刻!
多執行時的賣點很有趣,無論 Javascript 執行時如何,你都可以執行 Hono。在他們的存儲庫中,他們有適配器的概念,您可以在其中看到他們為每個執行時所做的調整。我認為這對於採用和擴大用戶群來說是巨大的,但實際上對於個人用戶來說,一旦將應用程式部署到雲端中,您可能不會切換執行時。
儘管 Hono 是輕量級的,開箱即用,但它有一堆中間件,包括第一方和第三方,您可以安裝它們來增強您的應用程式。這是在 Express 中流行的「當你想使用它時加入它」的方法。只要您的應用程式很小,這就可以很好地工作,但對於較大的應用程式,維護大量依賴項可能會令人沮喪。
Elysia 與 Encore 一樣,是為 TypeScript 建置的,並且還在 API 處理程序中提供類型安全性。了解 API 處理程序中正在使用的內容可以為您節省大量時間,而且不必在程式碼中進行類型檢查,這非常好。
您可以使用t
模組指定請求類型,該模組是TypeBox 驗證庫的擴充。與 Encore 不同,驗證發生在 JavaScript 層,這會增加一些效能開銷。
import { Elysia, t } from 'elysia'
new Elysia()
.patch("/profile", ({ body }) => body.profile, {
body: t.Object({
id: t.Number(),
profile: t.File({ type: "image" }),
}),
})
.listen(3000);
新增Swagger文件僅需要一行程式碼,且 Elysia 擁有對OpenTelemetry的第一方支援。這真的很好,因此無論平台如何,您都可以輕鬆監控您的應用程式。
艾莉西亞的速度很快!但不如 Encore 快,正如您將在下一節中看到的那樣。
Nest.js 與本次比較中的其他框架有點不同。 Encore、Elysia 和 Hono 嘗試提供用於建立端點和中間件的簡約 API,您可以按照自己的意願自由建立業務邏輯。 Nest.js更加固執己見,迫使您以某種方式建立程式碼。它提供了一個模組化架構,將程式碼組織成不同的抽象,如提供者、控制器、模組和中間件。
Nest 旨在使維護和開發更大的應用程式變得更加容易。但歸根結底,你是否喜歡 Nest 提供的固執己見的結構是非常主觀的。我想說,這對大型專案來說可能是有利的,因為長期可維護性比速度和簡單性更重要。對於只有少數開發人員的小型專案,增加抽象層級對於大多數用例來說可能是過度的。與 Hono、Encore 和 Elysia 相比,Nest 的固執己見也帶來了更陡峭的學習曲線。
使用 Nest 時,您可以選擇使用Express 或 Fastify作為底層 HTTP 伺服器框架。所有 Nest 功能都是在此基礎上新增的。
在選擇框架時,速度也許不是最重要的因素,但它也不容忽視。它將影響您的應用程式回應能力,並最終影響您的託管費用。
我們對沒有和有請求模式驗證的情況進行了基準測試,測量的是每秒的請求數。括號中的名稱是使用的請求驗證庫。 Encore.ts 內建了請求驗證。
在我們的基準測試中,Encore.ts 是所有框架中最快的,其次是 Elysia、Hono、Fastify 和 Express。 Nest 在底層使用 Fastify 或 Express,因此您可以預期 Nest 應用程式的效能與此相當,但可能會更慢,因為 Nest 會增加一些開銷。
Encore.ts 為何能如此快速?秘密在於 Encore.ts 有一個Rust 執行階段。 Rust 速度很快!
Encore.ts 實際上由兩個部分組成:
面向使用者的 TypeScript 部分,用於定義 API 和基礎架構。
在底層,它有一個用 Rust 寫的多執行緒執行時。
效能提升的關鍵是將盡可能多的工作從單執行緒 Node.js 事件循環轉移到 Rust 執行時。
例如,Rust 執行階段處理所有輸入/輸出,例如接受傳入的 HTTP 請求或從資料庫讀取。一旦請求或資料庫查詢被完全處理,它就會被移交給 Node.js 事件循環。
Hono、Elysia 和 Encore 對於如何建立程式碼沒有任何意見。這些框架之間建立 API 和中間件的方式非常相似。
這是每個框架的 GET 端點。當然存在一些差異,但如果我們仔細觀察,API 看起來非常相似。至少夠相似,在我看來這不是決定因素:
安可.ts
interface Response {
message: string;
}
export const get = api(
{ expose: true, method: "GET", path: "/hello/:name" },
async ({ name }: { name: string }): Promise<Response> => {
const msg = `Hello ${name}!`;
return { message: msg };
},
);
艾莉西亞
import { Elysia, t } from "elysia";
new Elysia()
.get(
"/hello/:name",
({ params }) => {
const msg = `Hello ${params.name}!`;
return { message: msg };
},
{
response: t.Object({
message: t.String(),
}),
},
)
連接
import { Hono } from "hono";
const app = new Hono();
app.get("/hello/:name", async (c) => {
const msg = `Hello ${c.req.param("name")}!`;
return c.json({ message: msg });
});
真正重要的是在建立健壯的應用程式時能夠依賴類型安全。 Encore 和 Elysia 提供類型安全的 API,但 Encore 在使用 Pub/Sub 等基礎架構時也提供編譯時類型安全性。使用 Encore,您還可以在呼叫另一個服務中的端點時獲得編譯時類型安全性。如果您曾經使用過微服務架構,那麼您就會知道這有多大。
Nest.js 是在 API 設計方面真正脫穎而出的一個。 Nest 應用中有很多概念和抽象。這既可能是好事,也可能是壞事,這實際上取決於您的偏好。查看 Nest 應用程式時,立即顯而易見的一件事是裝飾器的使用。 Nest 嚴重依賴裝飾器,例如使用依賴注入將服務注入控制器時。
巢控制器
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
就我個人而言,我並不是一個超級粉絲,而且我知道我不是唯一的粉絲。
所有這些框架的相似之處在於它們都可以部署到所有主流雲端平台(例如 Digital Ocean 和 Fly.io)或直接部署到 AWS 或 GCP 等雲端供應商。
Encore提供自動化的本地基礎架構。 encore run
啟動您的應用程式並啟動所有本機基礎設施,例如資料庫和 Pub/Sub 主題。忘掉 YAML、Docker Compose 和常見的令人頭痛的問題吧。
建立 Encore 應用程式時,您將獲得執行時配置,您可以在其中提供連接到雲端中的基礎架構所需的配置。
如果您想將 Encore 應用程式快速遷移到雲端並且不想自私自利,那麼您可以使用Encore Cloud 。 Encore Cloud 為拉取請求提供 CI/CD 和預覽環境。如果您願意,Encore Cloud 可以在 AWS 或 GCP 上您自己的雲端中配置所有所需的基礎架構。這意味著您的應用程式不依賴任何第三方服務,並且您可以完全控制所有基礎架構。
Hono 的突出之處在於它支援多種不同的執行時,因此在部署時您有很多選擇。部署到 Cloudflare Workers、Netlify 或 AWS Lambda 非常簡單,不需要大量設定。
使用Nest,您可以執行nest build
命令,將 TypeScript 程式碼編譯為 JavaScript。此過程會產生一個包含編譯檔案的dist
目錄。差不多就是這樣,然後您可以使用 Node.js 來執行您的dist
資料夾。
部署Elysia應用程式的建議方法是使用bun build
命令將應用程式編譯為二進位。一旦二進位檔案被編譯,你不需要在機器上安裝Bun
來執行伺服器。
就是這樣!希望您知道下一個專案中要採用什麼框架。
如果您想了解有關 Encore.ts 的更多訊息,可以查看 GitHub 上的開源專案: https ://github.com/encoredev/encore
建議:
{% 嵌入 https://dev.to/encore/choosing-the-right-tech-stack-a-developers-decision-making-guide-5gkd %}