Skip to content

presets(vercel): support immutable static files - #4432

Merged
pi0 merged 31 commits into
mainfrom
feat/vercel-immutable
Aug 20, 2026
Merged

presets(vercel): support immutable static files#4432
pi0 merged 31 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 NITRO_VERCEL_IMMUTABLE_STATIC_FILES_ENABLED

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 Error Error Jul 24, 2026 6:42pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Vercel immutable asset flow

Layer / File(s) Summary
Configuration and preset wiring
src/types/config.ts, src/presets/vercel/*
Adds immutable static-file configuration and configures both Vercel presets to set the asset directory during build:before.
Vite asset path and hash alignment
src/build/vite/plugin.ts
Aligns Vite client and SSR output with Nitro’s asset directory and lengthens applicable asset hash patterns.
Manifest generation and validation
src/presets/vercel/immutable.ts, test/presets/vercel.test.ts, test/fixture/nitro.config.ts, docs/2.deploy/20.providers/vercel.md
Creates the immutable namespace and immutable.json, validates generated output, and documents configuration and asset path behavior.

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

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

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.
Title check ⚠️ Warning The title is relevant, but it does not follow conventional commits because it uses a scope-like prefix without a valid type. Change it to a conventional commit format such as feat(vercel): support immutable static files.},{
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description is directly about enabling immutable static files for Vercel and matches the changeset.
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.
✨ Finishing Touches
🧪 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: 06a2e65

@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

Comment thread src/build/vite/env.ts Outdated
// `useLongerAssetHashes` in `plugin.ts`) so a `?url` asset import
// resolves to the same filename on both sides.
...(buildAssetsDir
? { assetFileNames: `${buildAssetsDir}/[name]-[hash:16][extname]` }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

TODO: We are still blindly overriding assetFileNames for server envs

@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 (1)
src/presets/vercel/immutable.ts (1)

60-75: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Sort the glob results before serializing the manifest. tinyglobby does not guarantee file order, so Object.fromEntries(files.map(...)) can produce different immutable.json bytes for the same asset set. Sorting files first keeps the manifest stable and avoids cache churn.

🤖 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/immutable.ts` around lines 60 - 75, Sort the files array
returned by glob before mapping it into the hashes object in the immutable
manifest generation flow. Update the files processing near ImmutableManifest so
identical asset sets always produce deterministic entry ordering and stable
immutable.json output.
🧹 Nitpick comments (1)
src/build/vite/plugin.ts (1)

493-527: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an options object for the helper configuration.

useLongerAssetHashes(build, isRolldown, assetsDir) has multiple positional configuration arguments. Use { isRolldown, assetsDir } as the second parameter to make call sites clearer and avoid future signature churn.

As per coding guidelines, multi-argument functions should use an options object as the second parameter.

Suggested shape
-export function useLongerAssetHashes(build, isRolldown, assetsDir)
+export function useLongerAssetHashes(
+  build,
+  { isRolldown, assetsDir }: { isRolldown: boolean | undefined; assetsDir: string }
+)
🤖 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/build/vite/plugin.ts` around lines 493 - 527, Update useLongerAssetHashes
to accept a single options object containing isRolldown and assetsDir instead of
separate positional arguments, and adjust every call site to pass those named
properties while preserving the existing hash-upgrade behavior.

Source: Coding guidelines

🤖 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/immutable.ts`:
- Around line 60-75: Sort the files array returned by glob before mapping it
into the hashes object in the immutable manifest generation flow. Update the
files processing near ImmutableManifest so identical asset sets always produce
deterministic entry ordering and stable immutable.json output.

---

Nitpick comments:
In `@src/build/vite/plugin.ts`:
- Around line 493-527: Update useLongerAssetHashes to accept a single options
object containing isRolldown and assetsDir instead of separate positional
arguments, and adjust every call site to pass those named properties while
preserving the existing hash-upgrade behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 717b4f1c-51cd-4e18-9da6-c50ea050707a

📥 Commits

Reviewing files that changed from the base of the PR and between 6d61d11 and eb4f0d1.

📒 Files selected for processing (5)
  • docs/2.deploy/20.providers/vercel.md
  • src/build/vite/plugin.ts
  • 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 (2)
  • src/presets/vercel/types.ts
  • docs/2.deploy/20.providers/vercel.md

@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

🧹 Nitpick comments (1)
src/build/vite/plugin.ts (1)

511-515: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an options object for helper configuration.

useLongerAssetHashes adds configuration as positional parameters instead of using an options object as the second parameter, contrary to the repository guideline. Refactor the signature and its call sites before adding further options.

Suggested signature
 export function useLongerAssetHashes(
   build: NonNullable<EnvironmentOptions["build"]>,
-  isRolldown: boolean | undefined,
-  assetsDir: string,
-  opts?: { assetsOnly?: boolean }
+  {
+    isRolldown,
+    assetsDir,
+    assetsOnly = false,
+  }: {
+    isRolldown?: boolean;
+    assetsDir: string;
+    assetsOnly?: boolean;
+  }
 ): void {
🤖 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/build/vite/plugin.ts` around lines 511 - 515, Refactor
useLongerAssetHashes to accept a single options object for all helper
configuration, including the existing isRolldown, assetsDir, and optional
assetsOnly values. Update every call site to pass the equivalent named
properties, preserving current behavior and parameter values.

Source: Coding guidelines

🤖 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 `@src/build/vite/plugin.ts`:
- Around line 505-510: The output-options handling around the client/SSR
configuration must preserve explicitly configured entryFileNames,
chunkFileNames, and assetFileNames, including patterns containing [hash]. Only
populate fields that are undefined; move any longer-hash defaulting before
custom output patterns are applied, and update both affected branches without
rewriting user or plugin values.

---

Nitpick comments:
In `@src/build/vite/plugin.ts`:
- Around line 511-515: Refactor useLongerAssetHashes to accept a single options
object for all helper configuration, including the existing isRolldown,
assetsDir, and optional assetsOnly values. Update every call site to pass the
equivalent named properties, preserving current behavior and parameter values.
🪄 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: 0446596e-868a-480f-99ef-8b7a08e80e4d

📥 Commits

Reviewing files that changed from the base of the PR and between d60f636 and e6b0e71.

📒 Files selected for processing (1)
  • src/build/vite/plugin.ts

Comment thread src/build/vite/plugin.ts
- disable immutable static files (with a warning) on a non-root baseURL,
  since they must be served from the reserved `/_vercel/immutable/` path
- warn instead of silently writing an empty manifest when no assets are
  emitted under `buildAssetsDir`
- normalize `buildAssetsDir` in config and when deriving the immutable dir
- correct manifest comments and docs: values are file paths (explicitly
  allowed by the spec) and `VERCEL_HASH_SALT` is factored into the asset
  paths rather than the content hashes

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pi0
pi0 merged commit a14d9ff into main Aug 20, 2026
13 of 14 checks passed
@pi0
pi0 deleted the feat/vercel-immutable branch August 20, 2026 20:12
@pi0 pi0 mentioned this pull request Aug 21, 2026
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