跳到正文

go-like 同其他工具點樣分工 ​

公平比較要由 ownership 開始,唔係鬥功能數目。呢度講 ownership,即係邊個建立資源、邊個負責停佢、邊個觀察終態。NestJS、Fastify、Hono、Elysia、Koa 同 tRPC 處理 TypeScript application stack 嘅唔同層次;go-micro 同 go-kratos 就係 Go 生態嘅參考,transport 同 code generation 取向亦唔一樣。go-like 只係一組面向 TypeScript 嘅建構元件,重點係清楚 lifecycle、內部 unary call、provider contract 同跨 runtime 組合。

呢頁將證據分成幾個層級:

  • Source:目前 go-like checkout 暴露了所述 API 或邊界。
  • Pinned external:比較使用研究記錄中固定的 release、commit 或官方文件。這不是新跑的 benchmark,也不表示未固定版本的 main 分支沒有變動。
  • Declared:repository 中有範例或測試 lane。這不等於該 lane 已通過。
  • Gap:目前 repository 沒有證明相容性承諾。

本軌道使用的 go-like source baseline 是 commit 9385dbf5b6a7d913be56a80ade359e1bf9be8675。本地研究記錄中存在一個 go-micro commit 不一致:一筆比較記錄寫的是 9d306dcfc1a912a8a9493f31fee0bb983475258d,而詳細的固定版本備忘錄檢查的是 v6.9.0 的 3c39d17fadaa9ec21b671be4afef3e63846406e6。請當佢哋係要重新核對嘅比較輸入,唔好當成 upstream 而家嘅保證。

喺技術堆疊入面嘅位置 ​

工具主要解決的問題通常由它擁有的部分go-like 可以補充、但不取代的部分
NestJS依慣例驅動的 Node 應用程式框架Modules、providers、controllers、decorators、application context、framework lifecycle、HTTP 或 microservice adapter圍繞原生應用增加結構式 lifecycle boundary 或 internal call contract,前提是自行撰寫 bridge
FastifyNode HTTP server 與請求處理 pipelineRoute table、hooks、plugins、encapsulation、Node listener、request/reply objects圍繞 Fastify 擁有的資源增加 lifecycle 或 provider adapter
HonoWeb Standards 路由與 middlewareRoutes、middleware、sub-apps、app.fetch、runtime adapter 選擇Core App、明確的資源生命週期、內部 Client/Transport、服務探索
ElysiaBun 優先的 typed Web frameworkRoute tree、schema 組合、decorators、hooks、Bun 或 Web Standard adapter保留原生 Elysia 行為的同時增加 Core lifecycle 和內部 service building blocks
Koa精簡的 Node middleware kernelMiddleware stack 與 Node listener;router 通常由外部提供不再引入另一套路由器的前提下補上 lifecycle 和內部 service contract
tRPC型別安全的 procedure layerRouter/procedure paths、input/output parsers、context factory、HTTP/Fetch/WS adaptersProvider ownership、service discovery、selector policy、明確的 App lifecycle
go-microGo 微服務與 agent-oriented 生態Go Context、service/client/transport/registry/broker 抽象,以及額外的 agent/flow/MCP/A2A 範圍go-like 借用部分詞彙,不借用 Go ABI、goroutine 或 transport 相容性
go-kratosGo 雲原生服務框架App lifecycle、Go Context、HTTP/gRPC transports、middleware、registry、config、Protobuf/code generation基於 Protobuf-ES 嘅 Context-first 程式碼; /native 提供標準 gRPC 四種呼叫方式
go-like明確的 TypeScript 服務建構元件Context、App/Server lifecycle、standard Fetch edge、內部 Fetch JSON 與 SSE、Client/Server、Registry/Discovery/Selector、Config/Store/Cache/Broker/Health、adapters應用程式仍擁有框架路由、原生資料面、業務策略、auth(身分驗證與授權)與部署

因此,go-like 並不是要贏一場「誰的框架最大」的比較。真正的問題是:應用程式是否需要這些邊界保持明確,而且可以組合。

Ownership 矩陣 ​

關注點NestJSFastifyHono / Elysia / KoatRPCgo-like
外部 route tableControllers 與 decoratorsFastify instanceFramework instance 或外部 routerProcedure router,不是一般 REST routes外部 framework 或 application
Web handler ABIAdapter 擁有的 request/reply abstractionNode request/reply對 Hono 與 Web Standard adapter 而言,Standard Fetch 是核心Fetch/Node/Express/Fastify adapters標準的 (Request) => Response | Promise<Response>
Application lifecycleApplication context 與 hooksready、listen、close、hooksRuntime adapter 與 framework lifecycle 各不相同由 host/adapter 負責newApp、App.run、App.stop、hooks、結構式 Servers
Resource lifecycleContainer/framework hooksPlugin 與 server hooks由 application/runtime 負責由 application/adapter 負責明確的 Server.start(ctx) / stop(ctx) 契約與 adapter 所有權
Dependency compositionNest container/providersPlugin decoration 與 encapsulationContext/env 與組合;沒有通用 DI container明確的 context factory 與 router composition明確的 constructors 與 functional options;沒有 DI container
Internal transportMicroservice transports 與 framework adapters不是 service discovery 抽象不是 service discovery 抽象Procedure adapters 與可選 WebSocketTransport、Client、Listener、defineService、SSE ServerStream
Discovery 與 selectionTransport-specific 或外部提供外部提供外部提供外部提供Registry、Discovery、Watcher、Filters、五種 Selector 策略
RetryFramework 或 provider-specificApplication/plugin-specificApplication-specificMiddleware/adapter-specific預設一次;withRetry 需要授權與總嘗試次數
StreamingFramework/provider 選擇Node/Web stream 選擇原生 Web Streams 與 framework API取決於 adapter 的 HTTP/WSWeb Streams; JSON or SSE server stream; Fetch unary/server-streaming; /native client-streaming/bidi
Global instrumentationFramework/provider integrationPlugin ecosystemMiddleware ecosystemMiddleware/adapters明確的 wrapper;不安裝 global provider

前五列的標籤描述的是架構位置,不是品質排名。框架擁有 route table,在路由組合是主要問題時很有用;這只是和 go-like 把路由留給應用程式所做的不同所有權選擇。

Lifecycle 與 Context ​

目前 go-like source 定義了:

ts
interface Server {
  start(ctx: Context): Promise<void>
  stop(ctx: Context): Promise<void>
}

interface App {
  run(): Promise<void>
  stop(): Promise<void>
}

Server 契約是結構式的。只要 adapter 能誠實說明資源如何被接納、終態如何產生,原生 worker、listener、scheduler、訊息代理 subscription、logger destination 或 telemetry provider 都可以加入 Core。

go-like Context 同樣是結構式的,內部使用 AbortSignal。它暴露 deadline()、done()、err() 和 value(key),並提供 background、withCancel、withCancelCause、withTimeout、withDeadline、withoutCancel 與 withValue 等建構函式。

這和 Go 的明確 Context-first 風格相似,但與 context.Context 並不 ABI-compatible。Context 本身不提供 goroutines、channels 或 gRPC API。正確的遷移問題應該是「取消和所有權在哪裡跨過這個邊界?」,而不是「哪個型別名稱完全一樣?」

Core 不承諾 sibling Servers 按宣告的反向順序關閉。它會並行呼叫 sibling stop(ctx),接著等待 terminal start Promises 並彙整失敗。Nest application context、Fastify plugin graph、Elysia lifecycle 或 host adapter 可能有不同的順序與終態語意。比較時要看真正的擁有者,不要只看「graceful」這個標籤。

Transport 與服務呼叫 ​

go-like 的內部呼叫鏈是刻意拆開的:

text
Client
  -> Discovery snapshot, optional
  -> ordered Filter callbacks, optional
  -> Selector.select
  -> opaque ServiceEndpoint URL
  -> Transport.dial or resident logical owner
  -> fetch(Request)
  -> @go-like/server route and unary handler
  -> read Response
  -> feedback and owner release

typed Endpoint 把 Struct request/response validation 綁到JSON Fetch body。佢唔係 IDL,亦唔係產生式 protocol。withEndpoint(...) 會揀構造期直連快照;直連同發現快照會用同一個 Selector。程序內 Memory Transport 路徑仍然好適合作為第一個測試。

NestJS 的 microservice transport 選項、tRPC procedure adapter 與 Go framework transport,都不能直接和這張 DAG 互換。它們可能擁有不同的 route identity、serialization model、connection pool 或 retry layer。比較時應記錄這些差異,不要把所有名字裡有「RPC」的方框都當成同一種能力。

Retry 與 streaming 範圍 ​

最重要的反向比較是語意:

  • go-like 預設每次呼叫只嘗試一次。
  • withRetry(...) 要求提供 authorization: "idempotent" | "caller-approved"、正數的 maxAttempts 與 shouldRetry。
  • 這個 authorization 是呼叫方的宣告,不是系統證明操作具有冪等性。
  • 每次重試都會重新進入 discovery 與 selection,因此可能選到新的 endpoint。
  • 如果已經收到 response,但後續 feedback 或 cleanup 失敗,不會重新 replay 這次 response。

Go 比較研究記錄了不同的預設值與能力:go-micro 的 DefaultRetries 不能簡單說成「總共五次請求」,因為當 retry approval 仍為 true 時,它的 loop boundary 可能產生六次迭代;它的 public stream 形式與預設 CloseSend 實作也會隨 provider 改變。go-kratos 把 Protobuf/gRPC generation 與 HTTP streaming 形式結合,而 SSE 與 WebSocket 的方向和關閉行為並不相同。這些是 provider 與架構選擇,不是 go-like 少了幾個 flag。

對 go-like 來說:

text
Web framework or Fetch Handler
  -> Web Streams, SSE, or WebSocket behavior owned by the application/framework

go-like internal Client/Transport
  -> one JSON body, or one SSE server stream when `stream: true`
  -> not a bidirectional multi-frame protocol

@go-like/transport-grpc-buf
  -> Fetch: Connect/gRPC-Web unary and server-streaming
  -> /native: standard gRPC unary, server-streaming, client-streaming, bidi

Web ReadableStream 不是內部 RPC channel。不要把 streamed HTTP body 和多幀的 send/recv transport 當成同一個 feature。

Runtime 比較 ​

Runtime 問題go-like 證據比較時的結論
共用程式碼能否使用 Fetch 與 AbortSignal?Root Web 與選定的 transport/config provider 使用標準 Web API 或注入的 Fetch可以有相近的可攜性目標,但型別不會替 runtime 實作行為
自訂 PEM TLS、mTLS、ALPN 與 HTTP/2 能否透過 Fetch 可攜?Node transport 子路徑擁有原生能力;root Fetch path 不暴露所有控制項應比較 host 能力與 import path,而不只是 package 名稱
應用程式是否保留 framework router?Hono、Elysia 與 H3 範例都傳入原生 Fetch handlergo-like 是 framework route ownership 的補充
package version 是否證明已經發布?workspace:*, 0.0.1不能據此聲稱 npm 可用或生態成熟

目前 repository 有 Hono、Elysia、H3 與 vanilla Fetch 的直接 source 範例。沒有目前的 NestJS 或 Fastify bridge,也沒有對應的 compatibility suite。這些框架是遷移讀者的對象,不是已支援的直接整合。

按工具詳細比較 ​

NestJS ​

NestJS 是依慣例驅動的應用程式框架。它的 modules、providers、controllers、decorators、interceptors、pipes 與 application hooks 共同組成完整的 container 與 request model。go-like 沒有提供 Nest-compatible module container 或 controller bridge。

合理的整合邊界,是由應用程式自行圍繞 Nest application 或 host 實作一個結構式 Server adapter。這個 adapter 需要定義 Nest 何時已接納 listener、stop(ctx) 如何對應 Nest close,以及 timeout 後會發生什麼。目前 repository 沒有證明這類 bridge,因此文件不應展示直接呼叫 newNodeServer(nestApp, ...)。

Fastify ​

Fastify 擁有 route table、plugin encapsulation、hooks 與 Node listener。它的 plugin graph 很適合拿來比較 dependency scope,但 decorate 不是 Nest 風格的通用 provider container。go-like 不會自動把 Fastify 的 request/reply ABI 轉成 Fetch Handler,repository 目前也沒有測試 Fastify bridge。

保留 Fastify 的 routes 與 plugins。如果導入 go-like,就圍繞 Fastify owner 撰寫明確的結構式 Server,或自行實作獨立的 Fetch boundary。不要把 Fastify 自己的 request injection 或原生 shutdown 稱為 go-like Transport 或 Client 契約。

Hono ​

Hono 是目前已展示最清楚的互補關係。現有範例在 Hono 中建立 routes,把 app.fetch 傳給 newNodeServer,再把這個 host 放進 Core App。路由與 middleware 仍由 Hono 擁有;在應用程式選擇這樣做時,go-like 負責 host lifecycle boundary。

Elysia ​

Elysia 提供 Bun-first 的 route 與 schema composition,也在相關 adapter path 暴露 Web Standard handler。保留 Elysia 的 route tree、decorators、derives、hooks、streams 與 Bun-specific behavior。go-like 可以擁有 App 與明確的資源邊界,但不會把 .listen() 變成跨 runtime 的 go-like API。

Koa ​

Koa 是小型的 Node middleware kernel,不內建 router。這正好說明有些框架會刻意把更多 application composition 留在核心之外。go-like 不應該透過增加 router 來填補這個空缺。保留 Koa middleware 與外部 router,只在需要的地方增加 lifecycle 或內部呼叫邊界。

tRPC ​

tRPC 擁有型別安全的 procedure router 與 procedure middleware。它可以使用 Fetch、Node、Express、Fastify 或 WebSocket adapter,但它不是 Registry、Selector、connection pool 或 application lifecycle manager。go-like 的 typed Endpoint 是對 JSON Fetch body 做的較小 runtime Struct binding,不是另一個 procedure DSL,也不是產生式 IDL。

go-micro 與 go-kratos ​

這兩個 Go 專案可以作為 Context-first 呼叫、service lifecycle、Registry、Discovery、Selector 與 transport 詞彙的架構參考,但不是相容性目標:

  • Go context.Context 與 go-like Context 都強調明確取消,但 runtime 表示不同。
  • go-micro 的 Registry watcher model 與 go-like 的完整替換 snapshot,不應該被教成相同的 event stream。
  • @go-like/protoc-gen-like 基於 Protobuf-ES 產生 Context-first Protobuf RPC 程式碼。@go-like/transport-grpc-buf 嘅 Fetch 入口支援 Connect/gRPC-Web unary 同 server-streaming;/native 提供標準 gRPC 四種呼叫方式,包括 client-streaming 同 bidi。呢條路徑獨立於內部 Fetch/SSE 路徑。
  • go-micro 與 go-kratos 的 provider 預設值、retry loop、stream half-close 行為與 selector 預設值都與版本有關。發布新的比較版本前,應使用研究記錄中的 fixed upstream commit table 重新核對。

點樣揀 ​

如果你的主要問題是……先從……開始在這些情況下再加 go-like
Controllers、modules、decorators 和 DINestJS需要圍繞現有資源或內部服務呼叫增加明確邊界,而且願意自行撰寫 adapter
Node HTTP routes、hooks 和 plugin encapsulationFastify需要超出 host 的生命週期組合,或需要內部 unary service contract
跨 runtime 的 Web Standards routesHono需要 App/Server lifecycle、內部呼叫或 provider ownership
Bun-first 的 schema 和 route compositionElysia保留 Elysia 的同時,需要明確的 lifecycle 和 transport boundary
精簡的 Node middlewareKoa 加上一個 router需要補的是缺少的 lifecycle 或內部呼叫契約,而不是再加一個 router
型別安全的 procedurestRPC同時需要明確的 service discovery、provider ownership 或 Core lifecycle
Go 微服務堆疊go-micro 或 go-kratos正在建立獨立的 TypeScript 組合,而不是做 source-compatible port
跨 runtime 的 TypeScript 服務建構元件go-like只使用能解決目前邊界問題的 packages 與 providers

正確答案可能是兩套系統一起使用。當明確的所有權模型確實消除了一個實際歧義時,go-like 最有價值;一個已經完整的 framework application 若把每個 package 都加進來,就會違背小型建構元件的目標。

證據錨點 ​

本頁對 go-like 的判斷可以追溯到目前的 tree 與 package entrypoints:

  • README.md:產品範圍與明確排除項;
  • packages/core/src/app.ts:App、Server、startup、stop 與 timeout 行為;
  • packages/web/src/context.ts:標準 Handler 與 Context bridge;
  • packages/client/src/index.ts:Client options、pooling、retry 與 attempt pipeline;
  • packages/server/src/index.ts:內部 unary handlers 與 route dispatch;
  • packages/transport/src/types.ts 與 packages/transport/src/endpoint.ts:Fetch Request/Response 與 defineService 邊界;
  • packages/registry/src/types.ts 與 packages/registry/src/selector.ts:snapshots、filters、selectors 與 feedback。

研究記錄也保存了以下固定版本的外部比較輸入:

呢啲 URL 只係比較參考,唔代表今次文件階段重新抓過或者驗證過每一個 upstream 頁面。要改版本相關嘅比較內容之前,請重新核對 release tag 或 commit。