Node.js 框架综述 2024 — Elysia / Hono / Nest / Encore — 你应该选择哪一个?
Node.js Web 框架——我们从哪里开始呢?市面上有这么多选择,为你的项目选择合适的框架可能会让人不知所措。
在这篇文章中,我将带您了解Node.js 生态系统中最热门的框架,并分析每个框架的优势、劣势和最佳用例。
无论您追求的是速度、可扩展性还是简单性,我们都希望能够涵盖所有内容 - 因此到最后,您将确切地知道哪个框架适合您。
我们将要研究的框架是:Nest、Elysia、Encore.ts和Hono。
视频版本:
功能概述
按照从最轻量级到功能最丰富的等级,我会将框架定位如下:
这并不意味着轻量级不好,只是取决于你的项目需求。Hono 的轻量级特性实际上是它的卖点之一,不到 14KB 的大小非常适合部署到 Cloudflare Workers。
另一方面,Encore.ts具有许多内置功能,例如开箱即用的自动跟踪和本地基础设施。
让我们看一下每个框架,我们将从 Encore.ts 开始
安可
这是一个 开源 框架,旨在简化使用 TypeScript 构建健壮且类型安全的后端的过程。该框架内置了大量工具,可让您的开发体验更加流畅,性能也更加出色。在本次比较的所有框架中,它的速度最快。
类型安全的 API 模式 | CORS 处理 | 结构化日志记录 | 验证 |
发布/订阅集成 | 机密管理 | 基础设施整合 | 数据库集成 |
架构图 | 本地开发仪表板 | 服务目录 | TypeScript 原生 |
调试 | 错误处理 | 多线程 | 请求验证 |
追踪 | API 客户端生成 | 自动本地基础设施 | 自动化测试 |
Encore内置了请求验证功能。您在常规 TypeScript 中定义的请求和响应类型可用于在编译和运行时验证请求。与其他框架不同,Encore 的实际验证是在 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,您可以将基础架构作为类型安全的对象集成到应用程序代码中。创建数据库或发布/订阅主题只需几行应用程序代码。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 文档以及始终保持最新的系统架构图。
本地开发仪表板
值得一提的是,尽管 Encore 具有很多功能,但它却没有npm 依赖项。
霍诺
Hono是由Yusuke Wada创建的。他于 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 还完全没有NPM 依赖,这真的令人印象深刻!
多运行时的卖点很有意思,无论使用哪种 JavaScript 运行时,你都可以运行 Hono。在他们的代码库中,有一个适配器的概念,你可以看到他们针对每个运行时所做的调整。我认为这对应用的采用和用户群的增长至关重要,但实际上,对于个人用户来说,一旦将应用部署到云端,你可能不会再切换运行时。
尽管 Hono 轻量级,但它内置了大量的中间件,包括第一方和第三方的,您可以安装它们来增强您的应用。这种“需要用的时候再添加”的做法在 Express 中很流行。如果您的应用规模较小,这种方法效果很好;但对于规模较大的应用来说,维护大量的依赖项列表可能会令人沮丧。
艾丽西亚
Elysia 与 Encore 类似,都是为 TypeScript 构建的,并且在 API 处理程序中提供了类型安全。了解 API 处理程序内部的操作可以节省大量时间,而且无需在代码中反复进行类型检查,这一点非常棒。
您可以使用模块指定请求类型,该模块是TypeBox 验证库t
的扩展。与 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的第一方支持。这非常好,因此无论使用哪个平台,您都可以轻松监控您的应用程序。
Elysia 很快!但不如 Encore 快,下一节你会看到。
Nest.js
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 相当相似。至少在我看来,相似程度足以让这一点成为决定性因素:
安可
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 严重依赖装饰器,例如在使用依赖注入将服务注入到控制器时。
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
建议:


NestJS 与 Encore.ts:为您的 TypeScript 微服务选择正确的框架
Marcus Kohlberg 为 Encore 演唱 ・ 10 月 30 日


如何使用 Docker 和 Encore 将后端应用程序部署到 DigitalOcean
Marcus Kohlberg 为 Encore 演唱 ・ 10 月 23 日

