diff --git a/src/plugins/prerender-plugin.js b/src/plugins/prerender-plugin.js index 27972b1..2146235 100644 --- a/src/plugins/prerender-plugin.js +++ b/src/plugins/prerender-plugin.js @@ -65,6 +65,9 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere renderTarget ||= 'body'; additionalPrerenderRoutes ||= []; + const preloadHelperId = 'vite/preload-helper'; + const preloadPolyfillId = 'vite/modulepreload-polyfill'; + /** * From the non-external scripts in entry HTML document, find the one (if any) * that provides a `prerender` export @@ -107,6 +110,22 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere config.build.sourcemap = true; viteConfig = config; + + // We're only going to alter the chunking behavior in the default cases, where the user and/or + // other plugins haven't already configured this. It'd be impossible to avoid breakages otherwise. + if ( + Array.isArray(config.build.rollupOptions.output) || + config.build.rollupOptions.output?.manualChunks + ) { + return; + } + + config.build.rollupOptions.output ??= {}; + config.build.rollupOptions.output.manualChunks = (id) => { + if (id.includes(prerenderScript) || id.includes(preloadPolyfillId)) { + return "index"; + } + }; }, async options(opts) { if (!opts.input) return; @@ -123,15 +142,15 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere : { ...opts.input, prerenderEntry: prerenderScript }; opts.preserveEntrySignatures = 'allow-extension'; }, - // Injects a window check into Vite's preload helper, instantly resolving - // the module rather than attempting to add a to the document. + // Injects window checks into Vite's preload helper & modulepreload polyfill transform(code, id) { - // Vite keeps changing up the ID, best we can do for cross-version - // compat is an `includes` if (id.includes('vite/preload-helper')) { + // Injects a window check into Vite's preload helper, instantly resolving + // the module rather than attempting to add a to the document. + const s = new MagicString(code); + // Through v5.0.4 // https://github.com/vitejs/vite/blob/b93dfe3e08f56cafe2e549efd80285a12a3dc2f0/packages/vite/src/node/plugins/importAnalysisBuild.ts#L95-L98 - const s = new MagicString(code); s.replace( `if (!__VITE_IS_MODERN__ || !deps || deps.length === 0) {`, `if (!__VITE_IS_MODERN__ || !deps || deps.length === 0 || typeof window === 'undefined') {`, @@ -146,6 +165,23 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere code: s.toString(), map: s.generateMap({ hires: true }), }; + } else if (id.includes(preloadPolyfillId)) { + const s = new MagicString(code); + // Replacement for `'link'` && `"link"` as the output from their tooling has + // differed over the years. Should be better than switching to regex. + // https://github.com/vitejs/vite/blob/20fdf210ee0ac0824b2db74876527cb7f378a9e8/packages/vite/src/node/plugins/modulePreloadPolyfill.ts#L62 + s.replace( + `const relList = document.createElement('link').relList;`, + `if (typeof window === "undefined") return;\n const relList = document.createElement('link').relList;`, + ); + s.replace( + `const relList = document.createElement("link").relList;`, + `if (typeof window === "undefined") return;\n const relList = document.createElement("link").relList;`, + ); + return { + code: s.toString(), + map: s.generateMap({ hires: true }), + }; } }, async generateBundle(_opts, bundle) {