Skip to content

feat: add writeEarlyHints helper for HTTP 103 Early Hints support#378

Open
bilal-azam wants to merge 1 commit into
honojs:mainfrom
bilal-azam:feat/add-write-early-hints-helper
Open

feat: add writeEarlyHints helper for HTTP 103 Early Hints support#378
bilal-azam wants to merge 1 commit into
honojs:mainfrom
bilal-azam:feat/add-write-early-hints-helper

Conversation

@bilal-azam

Copy link
Copy Markdown

Summary

Implements 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.

Adds an exported writeEarlyHints(c, hints) helper that calls Node's native
response.writeEarlyHints() through the existing HttpBindings, letting
applications send preload/preconnect Link headers before the response is ready:

import { serve, writeEarlyHints } from '@hono/node-server'

app.get('/', async (c) => {
  writeEarlyHints(c, { link: ['</styles.css>; rel=preload; as=style'] })
  const page = await renderPage()
  return c.html(page)
})

Behaviour

  • Purely opt-in; zero changes to the existing response flow
  • Returns false (no-op) instead of throwing when: the runtime/Node version
    lacks writeEarlyHints, or headers are already sent — safe to call in code
    shared across runtimes
  • HTTP/2: [state verified behaviour with Node docs citation]
  • Minimum Node version: [state, reconciled with engines]

Tests

  • 103 + Link headers observed on the wire before the final response (HTTP/1)
  • Final response unaffected
  • Both no-op guard paths
  • [HTTP/2 test or guard test per verified support]

Docs

README section added with the preload example.

Closes [node-server tracking issue if opened]; ref honojs/hono#5046.

@usualoma

Copy link
Copy Markdown
Member

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:

  • I would avoid re-exporting this from the root entry point and expose it only from @hono/node-server/early-hints, consistent with subpath APIs such as serve-static and conninfo.
  • I’m also not convinced that writeEarlyHints should be public. It feels like a very thin abstraction over c.env.outgoing.writeEarlyHints(). Users who need imperative access can already use HttpBindings directly.
  • Regarding the middleware options, I agree with the current shape of accepting link directly. An API such as earlyHints({ hints: { link: '...' } }) could also be clean and more extensible, but in practice Link is likely to be the only header users need for Early Hints. The flatter API seems simpler and preferable:
  earlyHints({
    link: '</styles.css>; rel=preload; as=style',
  })

  earlyHints({
    link: (c) =>
      `</themes/${c.req.query('theme')}.css>; rel=preload; as=style`,
  })

Allowing string | string[] or a context-based function for link would cover both static and dynamic cases while staying consistent with other Hono middleware options.

I would also expect the middleware to warn only once per middleware instance when outgoing.writeEarlyHints is unavailable, then continue as a no-op. This would be similar to the unavailable-runtime behavior of Hono’s Cache middleware. It should also safely no-op if the response headers have already been sent.

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 link and the warn-once behavior.

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.

2 participants