astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
55 lines (54 loc) • 2.5 kB
JavaScript
const VIRTUAL_MODULE_ID = "astro:prefetch";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const prefetchInternalModuleFsSubpath = "astro/dist/prefetch/index.js";
const prefetchCode = `import { init } from 'astro/virtual-modules/prefetch.js';init()`;
export default function astroPrefetch({ settings }) {
const prefetchOption = settings.config.prefetch;
const prefetch = prefetchOption ? typeof prefetchOption === "object" ? prefetchOption : {} : undefined;
// Check against existing scripts as this plugin could be called multiple times
if (prefetch && settings.scripts.every((s) => s.content !== prefetchCode)) {
// Inject prefetch script to all pages
settings.scripts.push({
stage: "page",
content: `import { init } from 'astro/virtual-modules/prefetch.js';init()`
});
}
// Throw a normal error instead of an AstroError as Vite captures this in the plugin lifecycle
// and would generate a different stack trace itself through Vite's transform pipeline.
const throwPrefetchNotEnabledError = () => {
throw new Error("You need to enable the `prefetch` Astro config to import `astro:prefetch`");
};
return {
name: "astro:prefetch",
resolveId: {
filter: { id: new RegExp(`^${VIRTUAL_MODULE_ID}$`) },
handler() {
if (!prefetch) throwPrefetchNotEnabledError();
return RESOLVED_VIRTUAL_MODULE_ID;
}
},
load: {
filter: { id: new RegExp(`^${RESOLVED_VIRTUAL_MODULE_ID}$`) },
handler() {
if (!prefetch) throwPrefetchNotEnabledError();
return { code: `export { prefetch } from "astro/virtual-modules/prefetch.js";` };
}
},
transform: {
filter: {
// NOTE: Handle replacing the specifiers even if prefetch is disabled so View Transitions
// can import the internal module and not hit runtime issues.
id: new RegExp(`${prefetchInternalModuleFsSubpath}`) },
handler(code) {
// We perform a simple replacement with padding so that the code offset is not changed and
// we don't have to generate a sourcemap. This has the assumption that the replaced string
// will always be shorter than the search string to work.
code = code.replace("__PREFETCH_PREFETCH_ALL__", `${JSON.stringify(prefetch?.prefetchAll)}`.padEnd(25)).replace("__PREFETCH_DEFAULT_STRATEGY__", `${JSON.stringify(prefetch?.defaultStrategy)}`.padEnd(29)).replace("__EXPERIMENTAL_CLIENT_PRERENDER__", `${JSON.stringify(settings.config.experimental.clientPrerender)}`.padEnd(33));
return {
code,
map: null
};
}
}
};
}