@@ -10,7 +10,12 @@ import type { Plugin, ResolvedConfig } from "vite";
10
10
11
11
// Vite re-exports Rollup's type defs in newer versions,
12
12
// merge into above type import when we bump the Vite devDep
13
- import type { InputOption , OutputAsset , OutputChunk } from "rollup" ;
13
+ import type {
14
+ InputOption ,
15
+ OutputAsset ,
16
+ OutputChunk ,
17
+ OutputOptions ,
18
+ } from "rollup" ;
14
19
15
20
interface HeadElement {
16
21
type : string ;
@@ -74,6 +79,7 @@ export function PrerenderPlugin({
74
79
additionalPrerenderRoutes,
75
80
} : PrerenderPluginOptions = { } ) : Plugin {
76
81
const preloadHelperId = "vite/preload-helper" ;
82
+ const preloadPolyfillId = "vite/modulepreload-polyfill" ;
77
83
let viteConfig = { } as ResolvedConfig ;
78
84
let userEnabledSourceMaps : boolean | undefined ;
79
85
@@ -123,6 +129,34 @@ export function PrerenderPlugin({
123
129
config . build . sourcemap = true ;
124
130
125
131
viteConfig = config ;
132
+
133
+ // With this plugin adding an additional input, Rollup/Vite tries to be smart
134
+ // and extract our prerender script (which is often their main bundle) to a separate
135
+ // chunk that the entry & prerender chunks can depend on. Unfortunately, this means the
136
+ // first script the browser loads is the module preload polyfill & a sync import of the main
137
+ // bundle. This is obviously less than ideal as the main bundle should be directly referenced
138
+ // by the user's HTML to speed up loading a bit.
139
+
140
+ // We're only going to alter the chunking behavior in the default cases, where the user and/or
141
+ // other plugins haven't already configured this. It'd be impossible to avoid breakages otherwise.
142
+ if (
143
+ Array . isArray ( config . build . rollupOptions . output ) ||
144
+ ( config . build . rollupOptions . output as OutputOptions ) ?. manualChunks
145
+ ) {
146
+ return ;
147
+ }
148
+
149
+ config . build . rollupOptions . output ??= { } ;
150
+ ( config . build . rollupOptions . output as OutputOptions ) . manualChunks = (
151
+ id : string ,
152
+ ) => {
153
+ if (
154
+ id . includes ( prerenderScript as string ) ||
155
+ id . includes ( preloadPolyfillId )
156
+ ) {
157
+ return "index" ;
158
+ }
159
+ } ;
126
160
} ,
127
161
async options ( opts ) {
128
162
if ( ! opts . input ) return ;
@@ -139,15 +173,15 @@ export function PrerenderPlugin({
139
173
: { ...opts . input , prerenderEntry : prerenderScript } ;
140
174
opts . preserveEntrySignatures = "allow-extension" ;
141
175
} ,
142
- // Injects a window check into Vite's preload helper, instantly resolving
143
- // the module rather than attempting to add a <link> to the document.
176
+ // Injects window checks into Vite's preload helper & modulepreload polyfill
144
177
transform ( code , id ) {
145
- // Vite keeps changing up the ID, best we can do for cross-version
146
- // compat is an `includes`
147
178
if ( id . includes ( preloadHelperId ) ) {
179
+ // Injects a window check into Vite's preload helper, instantly resolving
180
+ // the module rather than attempting to add a <link> to the document.
181
+ const s = new MagicString ( code ) ;
182
+
148
183
// Through v5.0.4
149
184
// https://github.com/vitejs/vite/blob/b93dfe3e08f56cafe2e549efd80285a12a3dc2f0/packages/vite/src/node/plugins/importAnalysisBuild.ts#L95-L98
150
- const s = new MagicString ( code ) ;
151
185
s . replace (
152
186
`if (!__VITE_IS_MODERN__ || !deps || deps.length === 0) {` ,
153
187
`if (!__VITE_IS_MODERN__ || !deps || deps.length === 0 || typeof window === 'undefined') {` ,
@@ -162,6 +196,23 @@ export function PrerenderPlugin({
162
196
code : s . toString ( ) ,
163
197
map : s . generateMap ( { hires : true } ) ,
164
198
} ;
199
+ } else if ( id . includes ( preloadPolyfillId ) ) {
200
+ const s = new MagicString ( code ) ;
201
+ // Replacement for `'link'` && `"link"` as the output from their tooling has
202
+ // differed over the years. Should be better than switching to regex.
203
+ // https://github.com/vitejs/vite/blob/20fdf210ee0ac0824b2db74876527cb7f378a9e8/packages/vite/src/node/plugins/modulePreloadPolyfill.ts#L62
204
+ s . replace (
205
+ `const relList = document.createElement('link').relList;` ,
206
+ `if (typeof window === "undefined") return;\n const relList = document.createElement('link').relList;` ,
207
+ ) ;
208
+ s . replace (
209
+ `const relList = document.createElement("link").relList;` ,
210
+ `if (typeof window === "undefined") return;\n const relList = document.createElement("link").relList;` ,
211
+ ) ;
212
+ return {
213
+ code : s . toString ( ) ,
214
+ map : s . generateMap ( { hires : true } ) ,
215
+ } ;
165
216
}
166
217
} ,
167
218
async generateBundle ( _opts , bundle ) {
0 commit comments