[pull] canary from vercel:canary#878
Merged
pull[bot] merged 13 commits intocode:canaryfrom Mar 14, 2026
Merged
Conversation
Writing skills for guides and API reference for more consistent formatting. - `write-guide` - this skill helps create guides with progressive disclosure and a consistent format (intro, summary, step-by-step instructions, next steps). Works best when you give agents a demo. - `write-api-reference` - this skill looks at the API type (component, function, file, etc) and helps draft references following a consistent format. Works best when you give agents context. e.g. source code, PR descriptions, RFCs. Also explores repo context (e.g. e2e tests) Note: - While skills help you write a first draft, they’re 80%. Humans still need to check for accuracy, test APIs, and take it to 110%. - If no technical writing guidance is provided, skills work best when you give it references of past work. Closes: - https://linear.app/vercel/issue/DOC-6245/create-guide-skill - https://linear.app/vercel/issue/DOC-6246/create-api-reference-skill --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
) ### What? Switch Turbopack's hash encoding for chunk and asset output filenames from hexadecimal (base16) to base40, using the alphabet \`0-9 a-z _ - ~ .\`. Version hashes (used for HMR update comparison, not filenames) use base64 instead. ### Why? Base40 encodes the same number of bits in fewer characters than hex, producing shorter output filenames. All 40 characters are RFC 3986 unreserved (URL-safe) and safe on case-insensitive filesystems (macOS HFS+/APFS, Windows NTFS). Hash truncation lengths are reduced proportionally to maintain equivalent collision resistance: | Context | Before (hex) | After (base40) | Entropy | |---|---|---|---| | Content hash in chunk filenames | 16 chars | 13 chars | ~69 bits | | Content hash in asset filenames | 8 chars | 13 chars | ~69 bits | | Ident disambiguator hash | 8 chars | 7 chars | ~37 bits | | Long-path prefix hash | 5 chars | 4 chars | ~21 bits | ### How? **New encoding module** (\`turbo-tasks-hash/src/base40.rs\`): - Defines the base40 alphabet and length constants (\`BASE40_LEN_64 = 13\`, \`BASE40_LEN_128 = 25\`) - Implements a generic \`encode_base40_fixed<N>\` helper to avoid duplication - Public API: \`encode_base40(u64) -> String\` and \`encode_base40_128(u128) -> String\` **New base64 encoding** (\`turbo-tasks-hash/src/base64.rs\`): - \`encode_base64(u64) -> String\` — 11-char base64 (no padding) for version hashes - Version hashes don't appear in URLs or filenames, so base64 is safe and shorter **New \`HashAlgorithm\` variants** (\`turbo-tasks-hash/src/lib.rs\`): - \`Xxh3Hash64Base40\` and \`Xxh3Hash128Base40\` added alongside existing hex variants - Existing hex variants kept for internal manifests and identifiers **\`ContentHashing\` moved to \`turbopack-core\`**: - Moved from \`turbopack-browser\` to \`turbopack-core/src/chunk/mod.rs\` so both \`BrowserChunkingContext\` and \`NodeJsChunkingContext\` can use it **Separate chunk vs asset content hashing**: - \`BrowserChunkingContext\`: \`content_hashing\` renamed to \`chunk_content_hashing\` (optional), new \`asset_content_hashing: ContentHashing\` field (non-optional, defaults to 13 chars) - \`NodeJsChunkingContext\`: new \`asset_content_hashing: ContentHashing\` field (non-optional, defaults to 13 chars) - Builder methods: \`use_content_hashing()\` renamed to \`chunk_content_hashing()\`, new \`asset_content_hashing()\` **Version hashes switched to base64**: - \`turbopack-nodejs/src/ecmascript/node/version.rs\` - \`turbopack-dev-server/src/html.rs\` - \`turbopack-browser/src/ecmascript/version.rs\`, \`merged/version.rs\`, \`list/version.rs\` **Other callers updated** (15 files across turbopack and next-core): - All chunk/asset content hashing switched from \`Xxh3Hash128Hex\` → \`Xxh3Hash128Base40\` - \`ContentHashing::Direct { length }\` reduced from 16 → 13 - Asset path truncations use full 13-char base40 hash (matching chunk filenames) **Exception — \`wasm_edge_var_name\`** (\`turbopack-wasm/src/lib.rs\`): - Kept as \`Xxh3Hash128Hex\` because the hash is used as part of a JavaScript variable name (\`wasm_{hash}\`), and base40 characters \`-\`, \`~\`, \`.\` are not valid JS identifier characters. **Scope — NOT changed:** - Webpack configuration (unchanged) - Internal manifests (\`routes_hashes_manifest\`, \`project_asset_hashes_manifest\`) - Internal identifiers (font naming, external module hashing, data URI sources, debug IDs) - SRI hashes (SHA-based Base64, different purpose) --------- Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
1. This is misldeading in the bundle analyzer view 2. If you have a Nextjs app consisting of only API routes, then there is no need to ever write out any polyfill chunk.
…91188) Adds a dedicated test suite that asserts on the errors thrown when `cookies`, `headers`, `connection`, `draftMode`, and `next/root-params` are called inside `generateStaticParams`. Currently, these all fail because `generateStaticParams` runs without a work unit store. Each route is built individually using `--debug-build-paths` so we can capture and assert on the error for each API independently.
This auto-generated PR updates the production integration test manifest used when testing Rspack.
This auto-generated PR updates the development integration test manifest used when testing Rspack.
…e-stats.json (#90949) After a successful, Turbopack production build, this writes `.next/diagnostics/route-bundle-stats.json` containing First Load JS stats for every route. ## Why? We used to have route bundle size statistics print after every build. It was not very high-signal and could be misleading, often using heuristics to give a best-effort estimate of what sizes may be at runtime. **These kinds of metrics for route bundle sizes can be misleading, as pages can be slow to visual/interactive completeness even if they have small first load bytes.** However, a minimal gauge of how much JavaScript a route ships during initial page load can be a useful signal so long as users have additional context and awareness of their app structure. Let's provide just this number for now for those that could benefit. Additionally, this does so in the form of writing a json document to the build directory, rather than writing a table to stdout, where users have needed to write extra tools to parse. ## Format An array of route entries sorted descending by `firstLoadUncompressedJsBytes`: ```json [ { "route": "/blog/[slug]", "firstLoadUncompressedJsBytes": 124928, "firstLoadChunkPaths": [ ".next/static/chunks/framework.js", ".next/static/chunks/main.js", ".next/static/chunks/pages/blog/[slug].js" ] } ] ``` `firstLoadUncompressedJsBytes`: sum of uncompressed sizes of all JS chunks loaded on first navigation to the route (shared chunks included), for both Pages Router and App Router `firstLoadChunkPaths`: paths to those chunks relative to the project root ## Test Plan Added an integration test. Built with a create-next-app and verified the json document is written and the numbers align with what Chrome reports during initial load of a page.
@wbinnssmith added these scripts a long time ago at my suggestion/urging, but I think they ended up bad for a couple reasons that were hard to foresee at the time: - afsctool operates in-place and doesn't atomically write the compressed file, so if the process gets interrupted, your `target` directory is corrupted. https://github.com/Dr-Emann/applesauce is better for this reason. - This doesn't acquire the cargo lock, and modifying files while cargo is running is a good way to get corruption of the `target` directory. https://github.com/bgw/cargo-apfs-compress is my latest attempt at solving this, though I don't have a `LaunchAgents` config for it. Regarding `node_modules`: pnpm creates reflinks from a shared global store on apfs. Trying to compress these reflinked files is just going to hurt you because it'll break the data deduplication that would've otherwise happened.
…arams (#91158) Partial fallback upgrading is currently too broad. Any PPR fallback shell can be treated as upgradeable, including routes with no `generateStaticParams` and shells that are already as specific as prerendering can make them. In practice, that means we preserve `allowQuery` and enable background promotion for shells that should remain as partial fallbacks. That broadens the feature beyond the medium-cardinality case it was meant for and makes the build output imply per-param upgradeability when there are no prerenderable params left to fill. This PR teaches static-path generation to compute `remainingPrerenderableParams` for each fallback shell: the unresolved pathname params that can still be filled by `generateStaticParams` in that branch. We then use that signal to gate partial fallback behavior. With this change: - `partialFallback` is only emitted for shells that still have prerenderable params remaining - `allowQuery` with params is only preserved for those shells Effectively, this limits partial fallback upgrading to shells that can still be made more specific by prerendering.
saw the issue about the _document.tsx example not working. next/font cant be used in _document.tsx, it throws an error. removed that section from the docs since _app.tsx already has the correct example. fixes #88832 Co-authored-by: Kahfi Elhady <kahfie@gmail.com> Co-authored-by: Joseph <joseph.chamochumbi@vercel.com>
…91231) In #91158, I wired up the plumbing to indicate whether a partial fallback shell is upgradeable. The previous heuristic was too coarse. This wires up the handling in `next start`. This PR teaches the runtime to complete a fallback shell only as far as prerendering allows. Instead of promoting a generic shell like `/[one]/[two]` directly to `/c/foo`, it promotes it to the most specific prerendered shell for that branch, `/c/[two]`, where `[one]` has `generateStaticParams`. That means later requests can reuse the more complete shell, while fully dynamic params continue to stream as dynamic content. With this change: - the first request still serves the generic fallback shell immediately - the background revalidate writes a more specific shell, not a fully concrete route - later requests for the same prerendered branch reuse that shell - upgrading stops once only fully dynamic params remain This keeps the runtime behavior aligned with the build-time `remainingPrerenderableParams` contract from the downstack PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )