next.js
2251f438 - Turbopack: avoid document-wide selector scans when probing for chunk tags (#100047)

Commit
25 days ago
Turbopack: avoid document-wide selector scans when probing for chunk tags (#100047) ## Summary Fixes #99993. On the first non-runtime load of each chunk URL, Turbopack's browser DOM runtime checks whether a matching `<script>` or `<link rel=stylesheet>` already exists. That check was a document-wide `querySelectorAll` with four attribute and prefix selectors, so its cost grew with the size of the whole DOM. It runs on the main thread during hydration, roughly once per chunk. The selectors were also built by interpolating the URL without escaping: a decoded `"` threw a `SyntaxError`, and a `\` missed a tag that was already present. The production loader (`doLoadChunk`) and the dev backend (`unloadChunk` / `reloadChunk`) now look tags up with `getElementsByTagName` and plain string comparison. The helpers are defined once in the DOM backend and reused by the dev backend, since the runtime files are concatenated rather than imported as modules. Matching behavior is otherwise unchanged: - A tag matches if its raw attribute equals the chunk URL, or starts with the URL plus `?`, for both the URL and its `decodeURI` form. A different query string still does not match. - The stylesheet lookup still requires `rel` to be exactly `stylesheet` (ASCII case-insensitive). Dev CSS unload still ignores `rel`. - All matching tags are returned in document order, from both head and body. - Results are snapshot arrays, so removing tags while looping over them is safe. This lowers the cost per probe but is still proportional to the number of elements. A URL index that would make it independent of DOM size is out of scope here. ## Verification - New e2e test `test/e2e/app-dir/dynamic-chunk-dedupe`, passing with `pnpm test-start-turbo` and `pnpm test-dev-turbo`: - The fixture has server-rendered and `ssr: false` dynamic components, including CSS modules, and sets a `deploymentId` so chunk URLs carry `?dpl=`. - It asserts that styles apply, there are no page errors, each chunk is requested once, and the DOM has no duplicate chunk tags. - Sanity check: with the lookup deliberately broken, the DOM check failed on duplicate scripts and a duplicate stylesheet. - `pnpm test-start-turbo test/production/chunk-load-failure/chunk-load-failure.test.ts` (retry path): 3/3 - `pnpm test-dev-turbo test/development/css-hmr-unmounted-chunk test/development/app-dir/hmr-dynamic-component`: 7/7 - Snapshots regenerated with `UPDATE=1 cargo test -p turbopack-tests --test snapshot`. Only the runtime change appears in the diff, and 132/132 pass on rerun. - A Chromium harness compared the old selectors with the new lookups on 36 JS/CSS/unload cases. Results are identical except the `"` and `\` cases, which now match literally. - Sampled CPU profile on the issue's reproduction app at 4x CPU throttling (median of 5): probe time drops from 106.9 to 40.8 ms at about 4.3k elements, and from 215.9 to 51.6 ms at about 8.3k elements. <!-- NEXT_JS_LLM --> <!-- fleet 00169b97-050c-43e3-a74e-5c9141d0996e --> --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Author
Parents
Loading