From eac2d015154b2228b22490a1da2ebc6d629f88d2 Mon Sep 17 00:00:00 2001 From: rossrobino Date: Mon, 8 Jan 2024 12:03:22 -0500 Subject: [PATCH 01/13] feat: add experimental client prerender --- packages/astro/src/@types/astro.ts | 15 ++++++++ packages/astro/src/core/config/schema.ts | 5 +++ packages/astro/src/prefetch/index.ts | 34 ++++++++++++++++++- .../src/prefetch/vite-plugin-prefetch.ts | 6 +++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 97429212c698..089185024f36 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1566,6 +1566,21 @@ export interface AstroUserConfig { * ``` */ contentCollectionCache?: boolean; + + /** + * @docs + * @name experimental.clientPrerender + * @type {boolean} + * @default `false` + * @description + * Progressive enhancement to use the experimental Speculation Rules API + * when supported to prerender on the client. Use this setting to prerender the + * page on the client, including running client side JavaScript + * (see [unsafe prefetching](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API#unsafe_prefetching)). + * + * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) + */ + clientPrerender?: boolean; }; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 5d30d1b5305c..7be8043c08ab 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -58,6 +58,7 @@ const ASTRO_CONFIG_DEFAULTS = { experimental: { optimizeHoistedScript: false, contentCollectionCache: false, + clientPrerender: false, }, } satisfies AstroUserConfig & { server: { open: boolean } }; @@ -393,6 +394,10 @@ export const AstroConfigSchema = z.object({ .boolean() .optional() .default(ASTRO_CONFIG_DEFAULTS.experimental.contentCollectionCache), + clientPrerender: z + .boolean() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender), }) .strict( `Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for a list of all current experiments.` diff --git a/packages/astro/src/prefetch/index.ts b/packages/astro/src/prefetch/index.ts index 99cf3627af8e..d78e98e19d9b 100644 --- a/packages/astro/src/prefetch/index.ts +++ b/packages/astro/src/prefetch/index.ts @@ -16,6 +16,8 @@ const listenedAnchors = new WeakSet(); let prefetchAll: boolean = __PREFETCH_PREFETCH_ALL__; // @ts-expect-error injected global let defaultStrategy: string = __PREFETCH_DEFAULT_STRATEGY__; +// @ts-expect-error injected global +let clientPrerender: boolean = __EXPERIMENTAL_CLIENT_PRERENDER__; interface InitOptions { defaultStrategy?: string; @@ -216,7 +218,14 @@ export function prefetch(url: string, opts?: PrefetchOptions) { const priority = opts?.with ?? 'link'; debug?.(`[astro] Prefetching ${url} with ${priority}`); - if (priority === 'link') { + if ( + clientPrerender && + HTMLScriptElement.supports && + HTMLScriptElement.supports('speculationrules') + ) { + // this code is tree-shaken if unused + appendSpeculationRules(url); + } else if (priority === 'link') { const link = document.createElement('link'); link.rel = 'prefetch'; link.setAttribute('href', url); @@ -301,3 +310,26 @@ function onPageLoad(cb: () => void) { cb(); }); } + +/** + * Appends a `