@@ -296,6 +296,8 @@ export function createResponseState(
296296 const integrity =
297297 typeof scriptConfig === 'string' ? undefined : scriptConfig . integrity ;
298298
299+ preloadBootstrapModule ( resources , src ) ;
300+
299301 bootstrapChunks . push (
300302 startModuleSrc ,
301303 stringToChunk ( escapeTextForBrowser ( src ) ) ,
@@ -1886,7 +1888,7 @@ function pushLink(
18861888 }
18871889 }
18881890 pushLinkImpl ( resource . chunks , resource . props ) ;
1889- resources. usedStylesheets . add ( resource ) ;
1891+ resources. usedStylesheets . set ( key , resource ) ;
18901892 return pushLinkImpl ( target , props ) ;
18911893 } else {
18921894 // This stylesheet refers to a Resource and we create a new one if necessary
@@ -4158,8 +4160,7 @@ export function writePreamble(
41584160 // Flush unblocked stylesheets by precedence
41594161 resources . precedences . forEach ( flushAllStylesInPreamble , destination ) ;
41604162
4161- resources . usedStylesheets . forEach ( resource => {
4162- const key = getResourceKey ( resource . props . as , resource . props . href ) ;
4163+ resources . usedStylesheets . forEach ( ( resource , key ) => {
41634164 if ( resources . stylesMap . has ( key ) ) {
41644165 // The underlying stylesheet is represented both as a used stylesheet
41654166 // (a regular component we will attempt to preload) and as a StylesheetResource.
@@ -4254,8 +4255,7 @@ export function writeHoistables(
42544255 // but we want to kick off preloading as soon as possible
42554256 resources . precedences . forEach ( preloadLateStyles , destination ) ;
42564257
4257- resources . usedStylesheets . forEach ( resource => {
4258- const key = getResourceKey ( resource . props . as , resource . props . href ) ;
4258+ resources . usedStylesheets . forEach ( ( resource , key ) => {
42594259 if ( resources . stylesMap . has ( key ) ) {
42604260 // The underlying stylesheet is represented both as a used stylesheet
42614261 // (a regular component we will attempt to preload) and as a StylesheetResource.
@@ -4770,12 +4770,18 @@ type PreconnectProps = {
47704770} ;
47714771type PreconnectResource = TResource < 'preconnect' , null > ;
47724772
4773- type PreloadProps = {
4773+ type PreloadAsProps = {
47744774 rel : 'preload' ,
47754775 as : string ,
47764776 href : string ,
47774777 [ string ] : mixed ,
47784778} ;
4779+ type PreloadModuleProps = {
4780+ rel : 'modulepreload' ,
4781+ href : string ,
4782+ [ string ] : mixed ,
4783+ } ;
4784+ type PreloadProps = PreloadAsProps | PreloadModuleProps ;
47794785type PreloadResource = TResource < 'preload' , PreloadProps > ;
47804786
47814787type StylesheetProps = {
@@ -4820,7 +4826,7 @@ export type Resources = {
48204826 // usedImagePreloads: Set<PreloadResource>,
48214827 precedences : Map < string , Set < StyleResource> > ,
48224828 stylePrecedences : Map < string , StyleTagResource> ,
4823- usedStylesheets : Set < PreloadResource > ,
4829+ usedStylesheets : Map < string , PreloadResource> ,
48244830 scripts : Set < ScriptResource > ,
48254831 usedScripts : Set < PreloadResource > ,
48264832 explicitStylesheetPreloads : Set < PreloadResource > ,
@@ -4848,7 +4854,7 @@ export function createResources(): Resources {
48484854 // usedImagePreloads: new Set(),
48494855 precedences : new Map ( ) ,
48504856 stylePrecedences : new Map ( ) ,
4851- usedStylesheets : new Set ( ) ,
4857+ usedStylesheets : new Map ( ) ,
48524858 scripts : new Set ( ) ,
48534859 usedScripts : new Set ( ) ,
48544860 explicitStylesheetPreloads : new Set ( ) ,
@@ -5414,6 +5420,39 @@ function preloadBootstrapScript(resources: Resources, src: string): void {
54145420 pushLinkImpl ( resource . chunks , props ) ;
54155421}
54165422
5423+ // This function is only safe to call at Request start time since it assumes
5424+ // that each module has not already been preloaded. If we find a need to preload
5425+ // scripts at any other point in time we will need to check whether the preload
5426+ // already exists and not assume it
5427+ function preloadBootstrapModule ( resources : Resources , src : string ) : void {
5428+ const key = getResourceKey ( 'script' , src ) ;
5429+ if ( __DEV__ ) {
5430+ if ( resources . preloadsMap . has ( key ) ) {
5431+ // This is coded as a React error because it should be impossible for a userspace preload to preempt this call
5432+ // If a userspace preload can preempt it then this assumption is broken and we need to reconsider this strategy
5433+ // rather than instruct the user to not preload their bootstrap scripts themselves
5434+ console . error (
5435+ 'Internal React Error: React expected bootstrap module with src "%s" to not have been preloaded already. please file an issue' ,
5436+ src ,
5437+ ) ;
5438+ }
5439+ }
5440+ const props : PreloadModuleProps = {
5441+ rel : 'modulepreload ',
5442+ href : src ,
5443+ } ;
5444+ const resource : PreloadResource = {
5445+ type : 'preload' ,
5446+ chunks : [ ] ,
5447+ state : NoState ,
5448+ props,
5449+ } ;
5450+ resources . preloadsMap . set ( key , resource ) ;
5451+ resources . explicitScriptPreloads . add ( resource ) ;
5452+ pushLinkImpl ( resource . chunks , props ) ;
5453+ return ;
5454+ }
5455+
54175456function internalPreinitScript (
54185457 resources : Resources ,
54195458 src : string ,
0 commit comments