Pushing first-load JS to zero with Astro islands

From "async import" to "hydrate on demand" — what each of the three lazy-loading layers actually solves, with the code that runs on this site.

“Async import” is a vague phrase. It can mean at least three different things, and the payoff differs by an order of magnitude between them.

Layer one: route-level code splitting

The baseline. The bundler cuts each page into its own chunk, so opening /zh/games/snake downloads the snake and not 2048.

In Vite, import.meta.glob is all you need:

const loaders = {
  ...import.meta.glob('../games/*/App.vue'),
  ...import.meta.glob('../tools/*/App.vue'),
};

The catch: this glob has to be statically analysable. Build the path from a variable and the bundler gives up and ships one big bundle.

Layer two: deferring hydration

This layer is Astro’s own, and it is where it genuinely beats the docs-first frameworks.

In VitePress, defineAsyncComponent starts downloading when the component renders. Put twenty cards on a list page and twenty chunks fly out at once. Astro instead lets you write:

<GameShell client:visible />

client:visible means the code is not downloaded until the component scrolls into the viewport. There is also client:idle (browser idle), client:media (media query match) and client:only (skip SSR).

The widget below really does take that path — it is not hydrated yet, and only loads once you scroll it into view:

7x2 = 14

Layer three: on demand at runtime

The first two layers answer when to download. This one answers whether to.

Game engines, chart libraries, decoders inside a Web Worker — none of those belong in any first-load bundle. The compare mode in the JSON Studio tool works exactly this way: the diff algorithm is imported only after you actually press that button.

const mod = await import('./logic/diff');
diffEntries.value = mod.diffValues(left.value, right.value);

What it costs

Together, the three layers mean: content pages carry almost no JS, app pages are split per app, and heavy dependencies are split per interaction.

The price is build configuration and a mental model with three moving parts — you have to hold SSG, islands and client-side mounting in your head at the same time. For a site that has both articles and games, I think that price is worth paying.

← Back to all posts

Comments

…