From a8fa1d22e83260fb16134a3338d364dc81b9021e Mon Sep 17 00:00:00 2001
From: Speculator55005 <50082482+fas89@users.noreply.github.com>
Date: Mon, 14 Sep 2026 22:42:17 +0200
Subject: [PATCH] perf: navigation blocked on a chunk fetch because prefetch
was off
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**
`` 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.
---
docs/.vuepress/config.ts | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts
index bc3e7e8..4df3a7c 100644
--- a/docs/.vuepress/config.ts
+++ b/docs/.vuepress/config.ts
@@ -41,8 +41,29 @@ export default defineUserConfig({
bundler: viteBundler(),
- shouldPrefetch: false,
- shouldPreload: false,
+ // Both of these default to TRUE in VuePress. They were set to false in the
+ // initial commit with no rationale, and the cost is paid on every single
+ // navigation: with prefetch off the built HTML carries zero
+ // ``, so clicking through to a page blocks on fetching
+ // that page's chunk. Measured on the built site: 0 prefetch links across 213
+ // pages, against 310 chunks.
+ //
+ // Turning prefetch fully back on is not right either. 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/.
+ // Prefetching it for every visitor would trade one problem for a worse one.
+ //
+ // So: prefetch the route chunks (299 of the 310 are under 100 KB), and skip
+ // the editor. The remaining page chunks are what make navigation feel
+ // instant.
+ shouldPrefetch: (file, type) => {
+ if (type !== 'script') return false
+ return !/(?:ts|css|html|json)\.worker-|editor\.api-|(?:^|\/)vs-/.test(file)
+ },
+
+ // Preload only covers files the CURRENT page needs, so the default is simply
+ // correct - including on /playground/, where Monaco genuinely is needed.
+ shouldPreload: true,
head: [
// Favicon. This was `logo.png`, which is 69,734 bytes at 256x139 — a