@@ -32,7 +32,9 @@ const enum BundleImportState {
3232 None ,
3333 Low ,
3434 Queued ,
35+ /** Preload link was made */
3536 Loading ,
37+ /** All imports are >=Loading */
3638 Loaded ,
3739}
3840type BundleImport = {
@@ -41,14 +43,25 @@ type BundleImport = {
4143 $state$ : BundleImportState ;
4244 $imports$ : string [ ] ;
4345 $dynamicImports$ : string [ ] ;
44- $created$ ?: number | null ;
46+ $priority$ : boolean ;
47+ $created$ : number ;
48+ $waited$ : number ;
49+ $loaded$ : number ;
4550} ;
4651const bundles = new Map < string , BundleImport > ( ) ;
52+ let gotBundleGraph = false ;
4753const high : BundleImport [ ] = [ ] ;
4854const low : BundleImport [ ] = [ ] ;
4955
56+ let highCount = 0 ;
57+ let lowCount = 0 ;
58+ const loadStart = Date . now ( ) ;
59+
5060const log = ( ...args : any [ ] ) => {
51- console . log ( `PL> ${ high . length } hi ${ low . length } lo` , ...args ) ;
61+ console . log (
62+ `PL ${ Date . now ( ) - loadStart } > hi ${ highCount } /${ high . length } lo ${ lowCount } /${ low . length } ` ,
63+ ...args
64+ ) ;
5265} ;
5366let base : string | undefined ;
5467
@@ -61,24 +74,15 @@ const checkLoaded = (bundle: BundleImport) => {
6174 if ( bundle . $state$ === BundleImportState . Loaded ) {
6275 return true ;
6376 }
64- bundle . $imports$ = bundle . $imports$ . filter (
65- ( dep ) => bundles . get ( dep ) ! . $state$ !== BundleImportState . Loading
66- ) ;
67- bundle . $dynamicImports$ = bundle . $dynamicImports$ . filter (
68- ( dep ) => bundles . get ( dep ) ! . $state$ !== BundleImportState . Loading
69- ) ;
7077 if (
7178 bundle . $state$ === BundleImportState . Loading &&
72- ! bundle . $imports$ . length &&
73- ! bundle . $dynamicImports$ . length
79+ bundle . $imports$ . every ( ( dep ) => bundles . get ( dep ) ! . $state$ >= BundleImportState . Loading )
7480 ) {
7581 bundle . $state$ = BundleImportState . Loaded ;
7682 return true ;
7783 }
7884} ;
7985
80- let highCount = 0 ;
81- let lowCount = 0 ;
8286/**
8387 * This is called when a bundle is queued or finished loading.
8488 *
@@ -89,13 +93,22 @@ let lowCount = 0;
8993 */
9094const trigger = ( ) => {
9195 // high is confirmed needed so we go as wide as possible
92- while ( highCount < 20 && high . length ) {
96+ while ( high . length ) {
9397 const bundle = high . pop ( ) ! ;
9498 preloadOne ( bundle ! , true ) ;
9599 }
96- while ( highCount + lowCount < 3 && low . length ) {
97- const bundle = low . pop ( ) ! ;
98- preloadOne ( bundle ! ) ;
100+ // these are opportunistic
101+ if ( ! highCount && ! lowCount ) {
102+ while ( lowCount < 6 && low . length ) {
103+ const bundle = low . pop ( ) ! ;
104+ preloadOne ( bundle ! ) ;
105+ }
106+ }
107+ if ( ! high . length && ! low . length ) {
108+ const loaded = [ ...bundles . values ( ) ] . filter ( ( b ) => b . $state$ >= BundleImportState . Loading ) ;
109+ const waitTime = loaded . reduce ( ( acc , b ) => acc + b . $waited$ , 0 ) ;
110+ const loadTime = loaded . reduce ( ( acc , b ) => acc + b . $loaded$ , 0 ) ;
111+ log ( `done ${ loaded . length } total: ${ waitTime } ms waited, ${ loadTime } ms loaded` ) ;
99112 }
100113} ;
101114
@@ -108,50 +121,46 @@ const rel =
108121 * that slows down interaction
109122 */
110123const preloadOne = ( bundle : BundleImport , priority ?: boolean ) => {
111- if ( bundle . $state$ === BundleImportState . Loaded ) {
124+ if ( checkLoaded ( bundle ) ) {
112125 return ;
113126 }
114- if ( bundle . $url$ ) {
127+ if ( bundle . $state$ < BundleImportState . Loading ) {
115128 const start = Date . now ( ) ;
116- log (
117- `load ${ priority ? 'high' : 'low' } after ${ `${ start - bundle . $created$ ! } ms` } ` ,
118- bundle . $name$
119- ) ;
120- const link = doc . createElement ( 'link' ) ;
121- link . href = bundle . $url$ ! ;
122- link . rel = rel ;
123- if ( priority ) {
124- highCount ++ ;
125- } else {
126- lowCount ++ ;
127- }
128- link . as = 'script' ;
129- link . onload = link . onerror = ( ) => {
130- const end = Date . now ( ) ;
131- log ( `DONE ${ end - start } ms` , bundle . $name$ ) ;
132- link . remove ( ) ;
129+ bundle . $waited$ = start - bundle . $created$ ;
130+ bundle . $state$ = BundleImportState . Loading ;
131+ if ( bundle . $url$ ) {
132+ log ( `load ${ priority ? 'high' : 'low' } after ${ `${ bundle . $waited$ } ms` } ` , bundle . $name$ ) ;
133+ const link = doc . createElement ( 'link' ) ;
134+ link . href = bundle . $url$ ! ;
135+ link . rel = rel ;
133136 if ( priority ) {
134- highCount -- ;
137+ highCount ++ ;
135138 } else {
136- lowCount -- ;
139+ lowCount ++ ;
137140 }
138- trigger ( ) ;
139- } ;
141+ link . as = 'script' ;
142+ link . onload = link . onerror = ( ) => {
143+ const end = Date . now ( ) ;
144+ bundle . $loaded$ = end - start ;
145+ log ( `DONE ${ bundle . $priority$ ? 'high' : 'low' } ${ end - start } ms` , bundle . $name$ ) ;
146+ link . remove ( ) ;
147+ if ( priority ) {
148+ highCount -- ;
149+ } else {
150+ lowCount -- ;
151+ }
152+ trigger ( ) ;
153+ } ;
140154
141- doc . head . appendChild ( link ) ;
155+ doc . head . appendChild ( link ) ;
156+ }
142157 }
143158
144- bundle . $state$ = BundleImportState . Loading ;
145- if ( ! checkLoaded ( bundle ) ) {
146- /** Now that we processed the bundle, its dependencies are needed ASAP */
147- if ( priority ) {
148- // make sure to queue the high priority imports first so they preloaded before the low priority ones
149- preload ( bundle . $imports$ , priority ) ;
150- preload ( bundle . $dynamicImports$ ) ;
151- } else {
152- // only preload direct imports, low priority
153- preload ( bundle . $imports$ ) ;
154- }
159+ bundle . $priority$ ||= priority ! ;
160+ preload ( bundle . $imports$ , priority ) ;
161+ if ( bundle . $priority$ ) {
162+ // make sure to queue the high priority imports first so they preloaded before the low priority ones
163+ preload ( bundle . $dynamicImports$ ) ;
155164 }
156165} ;
157166
@@ -163,12 +172,18 @@ const makeBundle = (path: string, imports: string[], dynamicImports: string[]) =
163172 $state$ : BundleImportState . None ,
164173 $imports$ : imports ,
165174 $dynamicImports$ : dynamicImports ,
175+ $priority$ : false ,
166176 $created$ : Date . now ( ) ,
177+ $waited$ : 0 ,
178+ $loaded$ : 0 ,
167179 } ;
168180} ;
169181const ensureBundle = ( name : string ) => {
170182 let bundle = bundles . get ( name ) ;
171183 if ( ! bundle ) {
184+ if ( gotBundleGraph ) {
185+ return ;
186+ }
172187 bundle = makeBundle ( name , [ ] , [ ] ) ;
173188 bundles . set ( name , bundle ) ;
174189 }
@@ -179,11 +194,15 @@ const ensureBundle = (name: string) => {
179194} ;
180195
181196const parseBundleGraph = ( text : string ) => {
197+ log ( `parseBundleGraph ${ text . length >> 10 } kB` ) ;
182198 const graph = JSON . parse ( text ) as QwikBundleGraph ;
183199 let i = 0 ;
184200 // All existing loading bundles need imports processed
185201 const toProcess = Object . keys ( bundles )
186- . filter ( ( name ) => bundles . get ( name ) ! . $state$ === BundleImportState . Loading )
202+ . filter ( ( name ) => {
203+ const bundle = bundles . get ( name ) ! ;
204+ return bundle . $state$ === BundleImportState . Loading && bundle . $priority$ ;
205+ } )
187206 . reverse ( ) ;
188207 while ( i < graph . length ) {
189208 const name = graph [ i ++ ] as string ;
@@ -207,6 +226,8 @@ const parseBundleGraph = (text: string) => {
207226 bundles . set ( name , makeBundle ( name , imports , dynamicImports ) ) ;
208227 }
209228 }
229+ log ( `parseBundleGraph done ${ bundles . size } bundles` ) ;
230+ gotBundleGraph = true ;
210231 for ( const name of toProcess ) {
211232 const bundle = bundles . get ( name ) ! ;
212233 // we assume low priority
@@ -225,12 +246,17 @@ const preload = (name: string | string[], priority?: boolean) => {
225246 }
226247 const queue = priority ? high : low ;
227248 if ( Array . isArray ( name ) ) {
228- queue . push ( ...( name . map ( ensureBundle ) . filter ( Boolean ) as BundleImport [ ] ) . reverse ( ) ) ;
249+ const bundles = name . map ( ensureBundle ) . filter ( Boolean ) as BundleImport [ ] ;
250+ if ( ! bundles . length ) {
251+ return ;
252+ }
253+ queue . push ( ...bundles . reverse ( ) ) ;
229254 } else {
230255 const bundle = ensureBundle ( name ) ;
231- if ( bundle ) {
232- queue . push ( bundle ) ;
256+ if ( ! bundle ) {
257+ return ;
233258 }
259+ queue . push ( bundle ) ;
234260 }
235261 log ( `queue ${ priority ? 'high' : 'low' } ` , name ) ;
236262 trigger ( ) ;
0 commit comments