Skip to content

presets(vercel): support immutable static files#4432

Open
pi0x wants to merge 24 commits into
mainfrom
feat/vercel-immutable
Open

presets(vercel): support immutable static files#4432
pi0x wants to merge 24 commits into
mainfrom
feat/vercel-immutable

Conversation

@pi0x

@pi0x pi0x commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Draft docs:

https://nitrobuild-git-feat-vercel-immutable-nitrojs.vercel.app/deploy/providers/vercel#immutable-static-files

Preview package for e2e testing:

"nitro" : "https://pkg.pr.new/nitro@4432"

Then opt-in via vercel.immutableStaticFiles: true nitro config or VERCEL_IMMUTABLE_STATIC_FILES_ENABLED env var (vercel CI platform enables this by default so it is practically an opt-out!)

Local testing in examples:

NITRO_PRESET=vercel VERCEL_IMMUTABLE_STATIC_FILES_ENABLED=1 pnpm vite build
◐ Building [Client]                                                                                                                                                       nitro 6:33:53 PM
vite v8.1.4 building client environment for production...
✓ 29 modules transformed.
computing gzip size...
.vercel/output/static/_vercel/immutable/nitro/pages-D0nNC55o3cj-2ayC.css                      0.29 kB │ gzip:  0.16 kB
.vercel/output/static/_vercel/immutable/nitro/app-CqFtksZd3E5HpSno.css                        0.84 kB │ gzip:  0.41 kB
.vercel/output/static/_vercel/immutable/nitro/empty-assets-DxZrAOoFYWYgUY2K.js                0.04 kB │ gzip:  0.05 kB
.vercel/output/static/_vercel/immutable/nitro/_plugin-vue_export-helper-BDNMzG2s4PQA0d8h.js   0.08 kB │ gzip:  0.09 kB
.vercel/output/static/_vercel/immutable/nitro/not-found-CgjqGATp9RH0Q8le.js                   0.28 kB │ gzip:  0.24 kB
.vercel/output/static/_vercel/immutable/nitro/about-C1uMZwbD9fD3-tBM.js                       0.45 kB │ gzip:  0.34 kB
.vercel/output/static/_vercel/immutable/nitro/app-DP5SBsuu3loHg28I.js                         0.56 kB │ gzip:  0.36 kB
.vercel/output/static/_vercel/immutable/nitro/pages-C2JaCg3a3I8E0SJg.js                       0.57 kB │ gzip:  0.42 kB
.vercel/output/static/_vercel/immutable/nitro/entry-client-DPWvGVSjeqTUc8So.js               89.32 kB │ gzip: 34.85 kB

v2 backport: #4434

pi0 and others added 2 commits July 15, 2026 14:18
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nitro.build Ready Ready Preview, Comment Jul 16, 2026 1:40am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds optional Vercel immutable static-file support. Presets relocate generated assets, Vite aligns client and SSR paths with longer hashes, and builds emit an immutable.json manifest. Configuration and deployment behavior are documented.

Changes

Vercel immutable asset flow

Layer / File(s) Summary
Vercel configuration and preset wiring
src/types/config.ts, src/presets/vercel/types.ts, src/presets/vercel/preset.ts
Adds buildAssetsDir and immutableStaticFiles configuration, and enables immutable static-file output in both Vercel presets.
Vite asset path and hash alignment
src/build/vite/env.ts, src/build/vite/plugin.ts
Applies Nitro’s asset directory to client and SSR Vite builds and expands applicable bare hash tokens to longer hashes.
Immutable manifest generation and validation
src/presets/vercel/immutable.ts, src/presets/vercel/preset.ts, test/fixture/nitro.config.ts, test/presets/vercel.test.ts
Generates immutable.json from immutable public assets and verifies the configured directory and manifest structure.
Vercel deployment documentation
docs/2.deploy/20.providers/vercel.md
Documents configuration, hash salt behavior, immutable paths, and asset-directory requirements.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows a conventional-commit style and clearly matches the Vercel immutable static files change.
Description check ✅ Passed The description is clearly related to the Vercel immutable static files feature and its testing/docs.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vercel-immutable

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.

@pkg-pr-new

pkg-pr-new Bot commented Jul 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4432

commit: eb30da5

@pi0 pi0 changed the title feat: vercel immutable assets presets(vercel): support immutable assets Jul 15, 2026
@pi0
pi0 marked this pull request as ready for review July 15, 2026 17:52
@pi0
pi0 self-requested a review as a code owner July 15, 2026 17:52
@pi0 pi0 changed the title presets(vercel): support immutable assets presets(vercel): support immutable static files Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/presets/vercel/types.ts (1)

137-149: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the documented default match the opt-in implementation.

Line 145 says this is enabled by default, but Line 147 declares @default false, and the preset only enables it when VERCEL_IMMUTABLE_STATIC_FILES_ENABLED is set. Document it as disabled by default and opt-in, or change the implementation to default-on.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/presets/vercel/types.ts` around lines 137 - 149, Update the
`immutableStaticFiles` documentation in the Vercel preset options to
consistently describe the current opt-in behavior: state that it is disabled by
default and enabled only when configured, and change the conflicting `@default`
annotation accordingly. Leave the implementation unchanged.
src/presets/vercel/preset.ts (1)

124-124: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Fix the manifest hash values before enabling this hook.

generateImmutableManifest currently populates hashes with [url, url]; the values are URLs, not full content hashes as required by this feature’s contract and documentation. The resulting immutable.json is incorrect for both the serverless and static presets. Compute each emitted file’s digest before writing the manifest.

Also applies to: 160-162

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/presets/vercel/preset.ts` at line 124, Update generateImmutableManifest
and its callers in the serverless and static preset flows to compute a full
content digest for each emitted file before writing immutable.json, rather than
populating hashes with [url, url]. Ensure every manifest entry contains the file
URL and its computed hash, and only enable the hook after the corrected manifest
generation is in place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/presets/vercel/preset.ts`:
- Line 124: Update generateImmutableManifest and its callers in the serverless
and static preset flows to compute a full content digest for each emitted file
before writing immutable.json, rather than populating hashes with [url, url].
Ensure every manifest entry contains the file URL and its computed hash, and
only enable the hook after the corrected manifest generation is in place.

In `@src/presets/vercel/types.ts`:
- Around line 137-149: Update the `immutableStaticFiles` documentation in the
Vercel preset options to consistently describe the current opt-in behavior:
state that it is disabled by default and enabled only when configured, and
change the conflicting `@default` annotation accordingly. Leave the
implementation unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75f5c735-1087-44b8-898b-b4ba0a7a018e

📥 Commits

Reviewing files that changed from the base of the PR and between 43b5fa8 and e5e3730.

📒 Files selected for processing (4)
  • docs/2.deploy/20.providers/vercel.md
  • src/presets/vercel/immutable.ts
  • src/presets/vercel/preset.ts
  • src/presets/vercel/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/presets/vercel/immutable.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/presets/vercel/preset.ts (1)

29-29: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Parse the environment flag instead of coercing presence to boolean.

!! converts "false" and "0" into true, so users cannot disable immutable assets through the environment variable.

  • src/presets/vercel/preset.ts#L29-L29: explicitly parse VERCEL_IMMUTABLE_STATIC_FILES_ENABLED.
  • src/presets/vercel/preset.ts#L142-L142: apply the same parsing logic to vercel-static, preferably through a shared helper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/presets/vercel/preset.ts` at line 29, Parse
VERCEL_IMMUTABLE_STATIC_FILES_ENABLED as an actual environment boolean instead
of coercing its presence with !!, treating values such as "false" and "0" as
disabled. Apply the same parsing logic to the vercel-static configuration at
src/presets/vercel/preset.ts lines 29-29 and 142-142, preferably via a shared
helper.
🧹 Nitpick comments (1)
test/presets/vercel.test.ts (1)

467-468: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert manifest contents, not only its shape.

hashes: {} would satisfy these assertions, so the test would not catch a broken glob or URL mapping. Assert at least one expected asset entry and its generated URL.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/presets/vercel.test.ts` around lines 467 - 468, Strengthen the manifest
assertions in the test around manifest.version and manifest.hashes by verifying
that hashes contains at least one expected asset entry and that the entry has
the correct generated URL. Keep the existing version assertion and object-shape
check while ensuring broken glob or URL mapping behavior fails the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/presets/vercel.test.ts`:
- Line 462: The buildAssetsDir assertion in the Vercel preset test is hard-coded
despite immutableDir() incorporating VERCEL_HASH_SALT. Update the expectation to
derive the immutable path using the active VERCEL_HASH_SALT value, or isolate
the test by clearing that environment variable and restoring it afterward.

---

Outside diff comments:
In `@src/presets/vercel/preset.ts`:
- Line 29: Parse VERCEL_IMMUTABLE_STATIC_FILES_ENABLED as an actual environment
boolean instead of coercing its presence with !!, treating values such as
"false" and "0" as disabled. Apply the same parsing logic to the vercel-static
configuration at src/presets/vercel/preset.ts lines 29-29 and 142-142,
preferably via a shared helper.

---

Nitpick comments:
In `@test/presets/vercel.test.ts`:
- Around line 467-468: Strengthen the manifest assertions in the test around
manifest.version and manifest.hashes by verifying that hashes contains at least
one expected asset entry and that the entry has the correct generated URL. Keep
the existing version assertion and object-shape check while ensuring broken glob
or URL mapping behavior fails the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba51474d-6bcd-4384-bae0-46ff51f619a5

📥 Commits

Reviewing files that changed from the base of the PR and between e5e3730 and 8964eca.

📒 Files selected for processing (4)
  • src/presets/vercel/immutable.ts
  • src/presets/vercel/preset.ts
  • test/fixture/nitro.config.ts
  • test/presets/vercel.test.ts

Comment thread test/presets/vercel.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/presets/vercel.test.ts (1)

46-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use try/finally to guarantee environment restoration.

If the build/setup phase fails, the environment variable won't be restored, potentially leaking into cleanup hooks or other test suites in the same file. Consider wrapping the setup phase (between the override and the restoration) in a try/finally block to ensure process.env.VERCEL_HASH_SALT is always restored.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/presets/vercel.test.ts` around lines 46 - 50, Wrap the test setup and
execution between the VERCEL_HASH_SALT override and restoration in a try/finally
block, ensuring the existing restoration logic runs even when setup or
assertions fail. Keep the undefined case deleting process.env.VERCEL_HASH_SALT
and the defined case restoring its previous value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/presets/vercel.test.ts`:
- Around line 46-50: Wrap the test setup and execution between the
VERCEL_HASH_SALT override and restoration in a try/finally block, ensuring the
existing restoration logic runs even when setup or assertions fail. Keep the
undefined case deleting process.env.VERCEL_HASH_SALT and the defined case
restoring its previous value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 888ef528-c2dd-417d-a99c-a4b161934e0e

📥 Commits

Reviewing files that changed from the base of the PR and between ced17b8 and 02ee991.

📒 Files selected for processing (3)
  • src/build/vite/env.ts
  • src/build/vite/plugin.ts
  • test/presets/vercel.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/build/vite/env.ts
  • src/build/vite/plugin.ts

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.

3 participants