-
Notifications
You must be signed in to change notification settings - Fork 325
fix: support experimental.outputHashSalt config and NEXT_HASH_SALT env var #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ce767ac
c2f158b
3addb04
2a244ea
c28f71a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -273,6 +273,13 @@ export type ResolvedNextConfig = { | |
| * Set to 0 to disable in-memory caching entirely. | ||
| */ | ||
| cacheMaxMemorySize: number | undefined; | ||
| /** | ||
| * Concatenated hash salt from `experimental.outputHashSalt` config option | ||
| * and `NEXT_HASH_SALT` environment variable. Empty string when neither is set. | ||
| * When non-empty, mix into content-addressed output filenames so hash values | ||
| * change without modifying source — useful for cache-busting after CDN poisoning. | ||
| */ | ||
| hashSalt: string; | ||
| }; | ||
|
|
||
| const CONFIG_FILES = ["next.config.ts", "next.config.mjs", "next.config.js", "next.config.cjs"]; | ||
|
|
@@ -502,6 +509,7 @@ export async function resolveNextConfig( | |
| serverExternalPackages: [], | ||
| cacheHandler: undefined, | ||
| cacheMaxMemorySize: undefined, | ||
| hashSalt: process.env.NEXT_HASH_SALT ?? "", | ||
| buildId, | ||
| }; | ||
| detectNextIntlConfig(root, resolved); | ||
|
|
@@ -581,6 +589,11 @@ export async function resolveNextConfig( | |
| serverActionsConfig?.bodySizeLimit as string | number | undefined, | ||
| ); | ||
|
|
||
| // Resolve hashSalt from experimental.outputHashSalt config + NEXT_HASH_SALT env var. | ||
| // Next.js concatenates them: config value first, then env var. | ||
| const configOutputHashSalt = experimental?.outputHashSalt as string | undefined; | ||
| const hashSalt = (configOutputHashSalt ?? "") + (process.env.NEXT_HASH_SALT ?? ""); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The concatenation logic matches Next.js exactly ( Note: Next.js does the concatenation inside |
||
|
|
||
| // Resolve optimizePackageImports from experimental config | ||
| const rawOptimize = experimental?.optimizePackageImports; | ||
| const optimizePackageImports = Array.isArray(rawOptimize) | ||
|
|
@@ -674,6 +687,7 @@ export async function resolveNextConfig( | |
| serverExternalPackages, | ||
| cacheHandler, | ||
| cacheMaxMemorySize, | ||
| hashSalt, | ||
| buildId, | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3207,6 +3207,23 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] { | |
| }, | ||
| }; | ||
| })(), | ||
| // Mix experimental.outputHashSalt / NEXT_HASH_SALT into chunk content hashes. | ||
| // This changes output filenames (e.g., index-[hash].js) without modifying source. | ||
| // Uses augmentChunkHash (supported by Rolldown) instead of the unsupported output.hashSalt. | ||
| { | ||
| name: "vinext:hash-salt", | ||
| apply: "build", | ||
| augmentChunkHash() { | ||
| // Only apply to client environment; SSR/RSC don't use content hashing | ||
| if (this.environment?.name !== "client") return; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: the One thing to double-check: does the RSC plugin's multi-environment build pipeline call |
||
| const salt = nextConfig?.hashSalt; | ||
| if (salt) { | ||
| return salt; | ||
| } | ||
| }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scope gap: In Next.js,
The Next.js test suite (
This isn't a blocker — JS chunk salting is the primary use case and this PR delivers that correctly. But it would be good to:
Also, the comment on line 3212 says "supported by both Rollup (via crypto hash.update()) and Rolldown (via xxhash_base64_url)" — I'd soften this since the Rollup compatibility claim is hard to verify from the current deps (this project runs on Vite 8 / Rolldown, not Rollup). Simpler to just say "supported by Rolldown". |
||
| }, | ||
| // Note: augmentChunkHash only affects JS chunk hashes. CSS and static asset | ||
| // hashes are not salted, which is a known gap vs Next.js behavior. | ||
| // Write vinext-server.json to dist/server/ with a per-build prerender secret. | ||
| // The prerender secret is used by prod-server.ts to authenticate requests to | ||
| // the internal /__vinext/prerender/* endpoints, which are only reachable during | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this says "output content hashes" which implies all output files. Since the implementation only salts JS chunk hashes (via
augmentChunkHash), this detail could be more precise to avoid misleadingvinext checkoutput.