Skip to content

feat: add Hono example for Web Standards runtimes#106

Open
gmoon wants to merge 3 commits intomasterfrom
feat/hono-example
Open

feat: add Hono example for Web Standards runtimes#106
gmoon wants to merge 3 commits intomasterfrom
feat/hono-example

Conversation

@gmoon
Copy link
Copy Markdown
Owner

@gmoon gmoon commented Apr 27, 2026

Closes #104.

What

Adds `examples/hono-basic.ts` showing how v4's pure `proxy.fetch()`
drops into a Hono handler that returns a Web `Response`. Targets
Bun, Cloudflare Workers, Deno, and Node (via `@hono/node-server`).

```ts
app.on(['GET', 'HEAD'], '/*', async (c) => {
const url = new URL(c.req.url);
const { stream, status, headers } = await proxy.fetch({
url: url.pathname + url.search,
method: c.req.method,
headers: Object.fromEntries(c.req.raw.headers),
} as HttpRequest);
const body = Readable.toWeb(stream as Readable) as ReadableStream;
return new Response(body, { status, headers });
});
```

The decision (path A vs path B from #104)

Picked path A: adapt `Web Headers → Record` at the example
boundary with `Object.fromEntries`. The library API stays focused
on one header shape. Path B (widening `HttpRequest['headers']` to
`Headers | Record`) waits for a second framework to force it.

Smoke gate enhancement

`scripts/smoke-examples.sh` now also iterates `hono-basic.ts` and
adds a per-example latency baseline (10 sequential GETs of
`/index.html`, reports mean/max/p95). No threshold — visibility only.
Local run on this branch:

```
[smoke] OK: examples/express-basic.ts (... n=10 mean=55ms max=58ms p95=58ms)
[smoke] OK: examples/fastify-basic.ts (... n=10 mean=56ms max=59ms p95=59ms)
[smoke] OK: examples/hono-basic.ts (... n=10 mean=58ms max=80ms p95=80ms)
```

The numbers are within network jitter — confirms the "Hono on Node has
two extra conversion layers" overhead is in the noise vs S3 RTT for
network-bound streaming. README documents this honestly so the
inevitable "but Hono is slower" issue arrives with context.

Performance note (also in README)

On Node, Hono goes through `@hono/node-server` which converts
`IncomingMessage` ↔ `Web Request/Response` on every request — two
extra layers vs. Express's direct `stream.pipe(res)`. For
network-bound streaming the conversion is unmeasurable; for
sub-millisecond CPU-bound paths, prefer the Express/Fastify
examples. On Bun/Workers/Deno the conversion layer doesn't exist
at all.

Deliberately not in this PR

  • Path B (widening `HttpRequest` headers). Wait for a second framework.
  • Hono Docker integration (parallel to `fastify-docker.ts`). The library
    doesn't ship a Hono Docker variant; the integration tests target
    fastify-docker. Adding a Hono-Docker target is its own follow-up.
  • A "deploy to Cloudflare Workers" guide. Tutorial scope, separate doc.

Test plan

  • `npm run build` — clean
  • `npm test` — 49/49 (no test additions; the smoke gate is the example's gate)
  • `npm run type-check` — both `tsconfig.json` and `tsconfig.examples.json` clean
  • `npx biome check` — 0/0
  • `npm run test:smoke` — express + fastify + hono all pass with comparable latency
  • CI runs validation + performance against the Docker stack

Three commits

feat: add Hono example for Web Standards runtimes (closes #104)
test(smoke): wire Hono example into the gate; per-example latency baseline
docs: document Hono integration; add to framework compatibility list

🤖 Generated with Claude Code

gmoon and others added 3 commits April 27, 2026 09:36
s3proxy v4's pure proxy.fetch() returns { stream, status, headers } —
exactly what Web Response wants. examples/hono-basic.ts demonstrates
that on Bun, Cloudflare Workers, Deno, and Node (via @hono/node-server).

Two adapters are needed at the framework boundary (this is the
"Web Standards vs Node-shape" trade-off captured in #104):

  1. c.req.raw.headers (Web `Headers`) → Object.fromEntries → Record
     for HttpRequest.headers. Single-point conversion at the example;
     the library API stays focused on one header shape.
  2. proxy.fetch() returns a Node Readable; new Response() wants a Web
     ReadableStream. Readable.toWeb() bridges them with backpressure
     preserved end-to-end (no buffering).

Picked path (A) from #104: adapt at the example. Path (B) — widen
HttpRequest['headers'] to `Headers | Record` — waits for a second
framework to force it.

devDeps: hono, @hono/node-server. Both pinned within their stable
majors; engines unchanged (Node ≥22.13).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eline

- Add examples/hono-basic.ts to the smoke loop (alongside express, fastify).
  Same three-check contract: health=200, /index.html=200, missing=404.
- After the existing assertions, run N=10 sequential GETs of the known key
  and report mean/max/p95 latency per example. Visibility-only (no threshold
  gate) so CI surfaces a regression in any framework's framing path without
  flaking on network jitter. curl -m 5 already catches catastrophic hangs.
- p95 with N=10 collapses to max (no interpolation); commented inline.

Local run on this branch shows mean=55-58ms across all three frameworks,
confirming the "Hono is theoretically slower on Node" overhead is in the
noise vs S3 RTT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New "Hono Integration (Web Standards)" section parallel to the
  Express/Fastify ones, with the full handler shape (Object.fromEntries
  for headers, Readable.toWeb for the body, Web Response).
- Performance note: honest about the two-extra-layers cost on Node via
  @hono/node-server (IncomingMessage ↔ Web Request/Response), bounded
  to "unmeasurable for network-bound streaming" with the smoke gate's
  per-example latency baseline as supporting evidence. Recommends
  Express/Fastify for sub-ms CPU paths; Hono is the natural fit on
  Bun/Workers/Deno where the conversion layer doesn't exist.
- Hono added to "Framework Compatibility" list with ✅.
- examples/hono-basic.ts added to the project-structure listing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Hono example (and decide on Web Headers support)

1 participant