Skip to content

feat(writeEarlyHints): add Link: rel:preload headers as fallback#1288

Open
kricsleo wants to merge 1 commit intoh3js:mainfrom
kricsleo:feat/early-hints
Open

feat(writeEarlyHints): add Link: rel:preload headers as fallback#1288
kricsleo wants to merge 1 commit intoh3js:mainfrom
kricsleo:feat/early-hints

Conversation

@kricsleo
Copy link
Member

@kricsleo kricsleo commented Jan 25, 2026

resolves #1279

Summary by CodeRabbit

  • New Features

    • writeEarlyHints now supports array values for multiple hint entries.
  • Bug Fixes

    • Improved fallback behavior for environments lacking native early hints support by setting response headers for CDN compatibility.
  • Documentation

    • Added clarification about fallback behavior in non-native environments.
  • Tests

    • Added test coverage for writeEarlyHints functionality and fallback scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@kricsleo kricsleo requested a review from pi0 as a code owner January 25, 2026 12:57
@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

The PR enhances writeEarlyHints to support string array values and adds a fallback mechanism that converts hints to Link headers for CDNs when native early hints aren't available. Documentation and tests are updated accordingly.

Changes

Cohort / File(s) Change Summary
Core Implementation
src/utils/response.ts
Updated writeEarlyHints method signature to accept Record<string, string | string[]> instead of Record<string, string>; refactored to prefer native early hints when available, otherwise falls back to setting Link headers on response for CDN compatibility; added documentation comment clarifying fallback behavior
Documentation
docs/2.utils/2.response.md
Added explanatory note to "writeEarlyHints" section clarifying fallback behavior to response headers for CDNs when native early hints unavailable
Tests
test/utils.test.ts
Introduced comprehensive test suite for writeEarlyHints with node-target conditional skip; validates Link header fallbacks for single and multiple hint values across two test routes

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Early hints now dance with grace,
Across every runtime's space!
When native homes aren't there to stay,
Link headers light the way,
CDNs cache our preloads today! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding Link headers as a fallback for writeEarlyHints when native support is unavailable.
Linked Issues check ✅ Passed The PR implements the feature requested in issue #1279 by adding Link: rel=preload header fallbacks when native writeEarlyHints is unavailable.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the writeEarlyHints fallback feature: type signature update, implementation logic, documentation, and tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 25, 2026

Open in StackBlitz

npm i https://pkg.pr.new/h3js/h3@1288

commit: d1cdca3

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/utils/response.ts`:
- Around line 69-85: The fallback currently appends all hint headers from hints
into event.res.headers using event.res.headers.append, which can leak
undesirable headers (e.g., Set-Cookie); restrict the fallback to only propagate
Link headers: check for the "link" header key (case-insensitive) in hints and
append only those values (handling both string and string[] cases) via
event.res.headers.append, skipping any other hint names; keep the native early
hints branch (event.runtime?.node?.res?.writeEarlyHints) unchanged.

Comment on lines +69 to 85
// Use native early hints if available (Node.js)
if (event.runtime?.node?.res?.writeEarlyHints) {
return new Promise((resolve) => {
event.runtime?.node?.res?.writeEarlyHints(hints, () => resolve());
});
}

// Fallback: Set response headers for CDN support
for (const [name, value] of Object.entries(hints)) {
if (Array.isArray(value)) {
for (const v of value) {
event.res.headers.append(name, v);
}
} else {
event.res.headers.append(name, value);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restrict fallback to Link to avoid changing response semantics.

Early hints can include headers that shouldn’t become part of the final response (e.g., Set-Cookie, Cache-Control). The fallback currently appends all hint headers, which can unintentionally alter responses in non-node runtimes. Since the objective is a Link: rel=preload fallback, consider filtering to Link only.

🔧 Suggested change
-  for (const [name, value] of Object.entries(hints)) {
+  for (const [name, value] of Object.entries(hints)) {
+    if (name.toLowerCase() !== "link") {
+      continue;
+    }
     if (Array.isArray(value)) {
       for (const v of value) {
         event.res.headers.append(name, v);
       }
     } else {
       event.res.headers.append(name, value);
     }
   }
🤖 Prompt for AI Agents
In `@src/utils/response.ts` around lines 69 - 85, The fallback currently appends
all hint headers from hints into event.res.headers using
event.res.headers.append, which can leak undesirable headers (e.g., Set-Cookie);
restrict the fallback to only propagate Link headers: check for the "link"
header key (case-insensitive) in hints and append only those values (handling
both string and string[] cases) via event.res.headers.append, skipping any other
hint names; keep the native early hints branch
(event.runtime?.node?.res?.writeEarlyHints) unchanged.

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 Link: rel:preload header for writeEarlyHints

1 participant