@@ -29,6 +29,15 @@ import {
2929 ID ,
3030} from './hashed-file-mapping' ;
3131
32+ const HEAD_LINK_CLASS = 'hfm' ;
33+
34+ interface HeadLink {
35+ path : string ;
36+ rel : string ;
37+ as : string ;
38+ crossorigin ?: string ;
39+ }
40+
3241/**
3342 * Server-side implementation of {@link HashedFileMapping}.
3443 * Registers dynamically hashed files and stores them in index.html for the browser to use.
@@ -37,7 +46,7 @@ export class ServerHashedFileMapping extends HashedFileMapping {
3746 public readonly indexPath : string ;
3847 private readonly indexContent : string ;
3948
40- protected readonly headLinks : Set < string > = new Set ( ) ;
49+ protected readonly headLinks : Set < HeadLink > = new Set ( ) ;
4150
4251 constructor (
4352 private readonly root : string ,
@@ -114,7 +123,11 @@ export class ServerHashedFileMapping extends HashedFileMapping {
114123
115124 // We know this CSS is likely needed, so wecan avoid a FOUC by retrieving it in advance
116125 // Angular does the same for global styles, but doesn't "know" about out themes
117- this . addHeadLink ( p , 'prefetch' , 'style' ) ;
126+ this . addHeadLink ( {
127+ path : p ,
128+ rel : 'prefetch' ,
129+ as : 'style' ,
130+ } ) ;
118131
119132 this . ensureCompressedFilesAssumingUnchangedContent ( p , hp , '.br' ) ;
120133 this . ensureCompressedFilesAssumingUnchangedContent ( p , hp , '.gz' ) ;
@@ -124,14 +137,17 @@ export class ServerHashedFileMapping extends HashedFileMapping {
124137 /**
125138 * Include a head link for a given resource to the index HTML.
126139 */
127- addHeadLink ( path : string , rel : string , as : string , crossorigin ?: string ) {
128- const href = relative ( this . root , this . resolve ( path ) ) ;
140+ addHeadLink ( headLink : HeadLink ) {
141+ this . headLinks . add ( headLink ) ;
142+ }
129143
130- if ( hasValue ( crossorigin ) ) {
131- this . headLinks . add ( `< link rel=" ${ rel } " as=" ${ as } " crossorigin=" ${ crossorigin } " href=" ${ href } ">` ) ;
144+ private renderHeadLink ( link : HeadLink ) : string {
145+ const href = relative ( this . root , this . resolve ( link . path ) ) ;
132146
147+ if ( hasValue ( link . crossorigin ) ) {
148+ return `<link rel="${ link . rel } " as="${ link . as } " href="${ href } " crossorigin="${ link . crossorigin } " class="${ HEAD_LINK_CLASS } ">` ;
133149 } else {
134- this . headLinks . add ( `<link rel="${ rel } " as="${ as } " href="${ href } ">` ) ;
150+ return `<link rel="${ link . rel } " as="${ link . as } " href="${ href } " class=" ${ HEAD_LINK_CLASS } ">` ;
135151 }
136152 }
137153
@@ -156,15 +172,15 @@ export class ServerHashedFileMapping extends HashedFileMapping {
156172 } , { } ) ;
157173
158174 const root = parse ( this . indexContent ) ;
159- root . querySelector ( `script#${ ID } ` ) ?. remove ( ) ;
175+ root . querySelectorAll ( `script#${ ID } , link. ${ HEAD_LINK_CLASS } ` ) ?. forEach ( e => e . remove ( ) ) ;
160176 root . querySelector ( 'head' )
161177 . appendChild ( `<script id="${ ID } " type="application/json">${ JSON . stringify ( out ) } </script>` as any ) ;
162178
163179 for ( const headLink of this . headLinks ) {
164180 root . querySelector ( 'head' )
165- . appendChild ( headLink as any ) ;
181+ . appendChild ( this . renderHeadLink ( headLink ) as any ) ;
166182 }
167183
168- this . add ( this . indexPath , root . toString ( ) ) ;
184+ writeFileSync ( this . indexPath , root . toString ( ) ) ;
169185 }
170186}
0 commit comments