feat: add Early Hints (HTTP 103) middleware - #378
Conversation
|
Hi @bilal-azam, Thanks for working on this. I think the idea of supporting Early Hints as middleware makes sense. That said, my preference would be to keep the public API narrower:
earlyHints({
link: '</styles.css>; rel=preload; as=style',
})
earlyHints({
link: (c) =>
`</themes/${c.req.query('theme')}.css>; rel=preload; as=style`,
})Allowing I would also expect the middleware to warn only once per middleware instance when The existing HTTP/1.1 and HTTP/2 integration tests look valuable and should mostly remain reusable. They would mainly need to be adapted to the middleware-only API, with coverage added for a dynamic |
|
Thanks @usualoma, this all makes sense, and I agree with narrowing the surface. I'll rework it as middleware-only:
One question on the dynamic form: if the function returns undefined (or an empty array), I'm planning to skip sending hints entirely rather than emit an empty Link, let me know if you'd prefer different behaviour there. I'll push the rework shortly. |
Replace the exported writeEarlyHints helper with an earlyHints middleware exposed only from the ./early-hints subpath. Options are flattened to accept link as a string, array, or context function. Warns once per middleware instance when writeEarlyHints is unavailable and no-ops when headers are already sent.
|
Hi @bilal-azam, I also opened bilal-azam#1 with a few follow-up changes. Could you consider merging it into this PR?
|
feat(early-hints): improve typings and filter non-document requests
|
Thanks @usualoma, merged. The Sec-Fetch filtering is a good call; sending hints on fetch/XHR requests would just be wasted bytes, and failing open when the headers are absent keeps non-browser clients working. Good catch on the env.server unwrapping too. I'd missed that binding shape, and the Env generic makes the link callback properly typed for apps with custom bindings. Tests, build, and lint all pass locally after the merge, and I've updated the PR description to cover the new filtering behaviour. One small question: should the README mention the Sec-Fetch-Mode / Sec-Fetch-Dest filtering? Someone testing with fetch() or curl might wonder why no 103 appears. Happy to add a sentence if you think it's worth documenting. |
|
Hi @bilal-azam,
First of all, when using |
|
You're right; they don't send Sec-Fetch-* at all, so they fall through the "allow when absent" branch and do receive a 103. The confusing case is the opposite of what I had in mind. I've added a short note to the README covering both directions. |
|
Hi @bilal-azam, Hi @yusukebe, |
Summary
Adds Early Hints (HTTP 103) support at the runtime layer, following @yusukebe's
direction in honojs/hono#5046 that this belongs in the runtime adapter rather
than Hono core.
Exposes an
earlyHintsmiddleware from@hono/node-server/early-hintsthatsends preload/preconnect
Linkheaders before the handler's response is ready,using Node's native
response.writeEarlyHints()via the existingHttpBindings.API
linkacceptsstring | string[] | ((c: Context) => string | string[] | undefined).Returning
undefinedor an empty array skips sending hints.Behaviour
./early-hintssubpath, consistent withserve-staticand
conninfo— nothing added to the root entryoutgoing.writeEarlyHintsisunavailable, then continues as a no-op (matching the Cache middleware's
unavailable-runtime behaviour). This guard covers non-Node runtimes and
non-HTTP bindings —
writeEarlyHintshas existed since Node 18.11 and thispackage requires Node >= 20
Sec-Fetch-Modeand
Sec-Fetch-Dest; requests missing either header are allowed through, sonon-browser clients still work
Tests
Linkobserved on the wirebefore the final response
linkfunction receives the Context and its result is senta separate instance warns again
undefined/empty returndest-only) and an
Envpreservation type assertionChanges from the initial version
Reworked per @usualoma's review: removed the public
writeEarlyHintshelper andthe root re-export in favour of a middleware-only API on the
./early-hintssubpath, flattened the options, and added dynamic-
linkand warn-oncebehaviour with tests.
Ref honojs/hono#5046.