perf: navigation blocked on a chunk fetch because prefetch was off - #122
Merged
Merged
Conversation
Reported symptom: switching between pages feels slow. Confirmed, with a cause. `shouldPrefetch` and `shouldPreload` both DEFAULT TO TRUE in VuePress. This repo set both to false in the initial commit, in April, with no comment. The cost is paid on every navigation: with prefetch off the built site carries **zero** `<link rel="prefetch">` across 213 pages, so clicking a link blocks on fetching that page's chunk - one network round trip before anything renders. Measured on the built output: 0 prefetch links against 310 chunks. I could not reproduce the latency locally, and should say so: served from localhost there is no round trip to pay. The mechanism is certain from the built HTML; the felt slowness needs a real network, which is where it was reported. **Turning it fully back on would have been worse.** Of 19 MB of chunks, 12.4 MB is Monaco - the ts / css / html / json workers plus `editor.api` and `vs` - and that is reachable only from /playground/. The VuePress default of `true` would prefetch all of it for every visitor. So `shouldPrefetch` is now the documented function form, `(file, type) => boolean`, prefetching script chunks and skipping the editor. Result on a deep page: 214 prefetch links, 4.87 MB, and **0 Monaco chunks**. That is cached after the first page rather than paid per navigation, and it is strictly less than the framework default, not more. `shouldPreload` returns to `true`, its default. Preload only covers files the CURRENT page needs, so it is correct everywhere including /playground/, where Monaco genuinely is required. Verified: the playground still references its chunk and NOT Monaco's in HTML, both worker bundles still exist for on-demand load, and the build is green. Considered and rejected: quicklink and instant.page both solve this well, but they add a runtime dependency to do what the framework already exposes, and neither can see chunk names - so neither could have excluded Monaco, which is the whole difficulty here.
This branch was successfully deployed
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Reported symptom: switching between pages feels slow. Confirmed, with a cause.
The cause
shouldPrefetchandshouldPreloadboth default totruein VuePress. This repo set both tofalsein the initial commit, in April, with no comment explaining why.The cost is paid on every navigation. With prefetch off the built site carries zero
<link rel="prefetch">across 213 pages, so clicking a link blocks on fetching that page's chunk — a full network round trip before anything renders.My first hypothesis was wrong and worth recording: I assumed it was disabled to stop Monaco being prefetched.
git log -S shouldPrefetchshows it predates the playground entirely. There was never a reason.Why turning it back on would have been worse
Of 19 MB of chunks, 12.4 MB is Monaco — the
ts/css/html/jsonworkers pluseditor.apiandvs— reachable only from/playground/.shouldPrefetch: truewould prefetch all of it for every visitor, trading one problem for a worse one.The fix
The documented function form,
(file, type) => boolean: prefetch script chunks, skip the editor. 299 of the 310 chunks are under 100 KB and are exactly the route chunks that make navigation feel instant.That is strictly less than the framework default, not more aggressive than it.
shouldPreloadreturns totrue. Preload only covers files the current page needs, so the default is correct everywhere — including/playground/, where Monaco genuinely is required.Verification
reels/*.htmlassets, not VuePress pages)/playground/still references its own chunk and not Monaco's in HTML; both worker bundles still exist for on-demand load<link rel="prefetch">href on a deep page: 0 matches againstts.worker,css.worker,html.worker,json.worker,editor.api,vs-One honest limit
I could not reproduce the latency locally — served from localhost there is no round trip to pay. The mechanism is certain from the built HTML; the felt improvement needs a real network, which is where it was reported. Worth confirming once this deploys.
Considered and rejected
quicklink (viewport + idle) and instant.page (65 ms hover) both solve this well, but they add a runtime dependency to do what the framework already exposes natively — and neither can see chunk names, so neither could have excluded Monaco, which is the entire difficulty here.