@@ -20,7 +20,6 @@ import {
2020 formatMessages ,
2121} from 'esbuild' ;
2222import { basename , extname , relative } from 'node:path' ;
23- import { FileInfo } from '../../utils/index-file/augment-index-html' ;
2423
2524export type BundleContextResult =
2625 | { errors : Message [ ] ; warnings : Message [ ] }
@@ -29,7 +28,7 @@ export type BundleContextResult =
2928 warnings : Message [ ] ;
3029 metafile : Metafile ;
3130 outputFiles : OutputFile [ ] ;
32- initialFiles : FileInfo [ ] ;
31+ initialFiles : Map < string , InitialFileRecord > ;
3332 } ;
3433
3534/**
@@ -41,11 +40,23 @@ export function isEsBuildFailure(value: unknown): value is BuildFailure {
4140 return ! ! value && typeof value === 'object' && 'errors' in value && 'warnings' in value ;
4241}
4342
43+ export interface InitialFileRecord {
44+ entrypoint : boolean ;
45+ name ?: string ;
46+ type : 'script' | 'style' ;
47+ external ?: boolean ;
48+ }
49+
4450export class BundlerContext {
4551 #esbuildContext?: BuildContext < { metafile : true ; write : false } > ;
4652 #esbuildOptions: BuildOptions & { metafile : true ; write : false } ;
4753
48- constructor ( private workspaceRoot : string , private incremental : boolean , options : BuildOptions ) {
54+ constructor (
55+ private workspaceRoot : string ,
56+ private incremental : boolean ,
57+ options : BuildOptions ,
58+ private initialFilter ?: ( initial : Readonly < InitialFileRecord > ) => boolean ,
59+ ) {
4960 this . #esbuildOptions = {
5061 ...options ,
5162 metafile : true ,
@@ -64,7 +75,7 @@ export class BundlerContext {
6475 let errors : Message [ ] | undefined ;
6576 const warnings : Message [ ] = [ ] ;
6677 const metafile : Metafile = { inputs : { } , outputs : { } } ;
67- const initialFiles = [ ] ;
78+ const initialFiles = new Map < string , InitialFileRecord > ( ) ;
6879 const outputFiles = [ ] ;
6980 for ( const result of individualResults ) {
7081 warnings . push ( ...result . warnings ) ;
@@ -80,7 +91,7 @@ export class BundlerContext {
8091 metafile . outputs = { ...metafile . outputs , ...result . metafile . outputs } ;
8192 }
8293
83- initialFiles . push ( ... result . initialFiles ) ;
94+ result . initialFiles . forEach ( ( value , key ) => initialFiles . set ( key , value ) ) ;
8495 outputFiles . push ( ...result . outputFiles ) ;
8596 }
8697
@@ -139,27 +150,59 @@ export class BundlerContext {
139150 }
140151
141152 // Find all initial files
142- const initialFiles : FileInfo [ ] = [ ] ;
153+ const initialFiles = new Map < string , InitialFileRecord > ( ) ;
143154 for ( const outputFile of result . outputFiles ) {
144155 // Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot
145156 const relativeFilePath = relative ( this . workspaceRoot , outputFile . path ) ;
146- const entryPoint = result . metafile ? .outputs [ relativeFilePath ] ?. entryPoint ;
157+ const entryPoint = result . metafile . outputs [ relativeFilePath ] ?. entryPoint ;
147158
148159 outputFile . path = relativeFilePath ;
149160
150161 if ( entryPoint ) {
151162 // The first part of the filename is the name of file (e.g., "polyfills" for "polyfills.7S5G3MDY.js")
152- const name = basename ( outputFile . path ) . split ( '.' , 1 ) [ 0 ] ;
163+ const name = basename ( relativeFilePath ) . split ( '.' , 1 ) [ 0 ] ;
164+ // Entry points are only styles or scripts
165+ const type = extname ( relativeFilePath ) === '.css' ? 'style' : 'script' ;
153166
154167 // Only entrypoints with an entry in the options are initial files.
155168 // Dynamic imports also have an entryPoint value in the meta file.
156169 if ( ( this . #esbuildOptions. entryPoints as Record < string , string > ) ?. [ name ] ) {
157170 // An entryPoint value indicates an initial file
158- initialFiles . push ( {
159- file : outputFile . path ,
171+ const record : InitialFileRecord = {
160172 name,
161- extension : extname ( outputFile . path ) ,
162- } ) ;
173+ type,
174+ entrypoint : true ,
175+ } ;
176+
177+ if ( ! this . initialFilter || this . initialFilter ( record ) ) {
178+ initialFiles . set ( relativeFilePath , record ) ;
179+ }
180+ }
181+ }
182+ }
183+
184+ // Analyze for transitive initial files
185+ const files = [ ...initialFiles . keys ( ) ] ;
186+ for ( const file of files ) {
187+ for ( const initialImport of result . metafile . outputs [ file ] . imports ) {
188+ if ( initialFiles . has ( initialImport . path ) ) {
189+ continue ;
190+ }
191+
192+ if ( initialImport . kind === 'import-statement' || initialImport . kind === 'import-rule' ) {
193+ const record : InitialFileRecord = {
194+ type : initialImport . kind === 'import-rule' ? 'style' : 'script' ,
195+ entrypoint : false ,
196+ external : initialImport . external ,
197+ } ;
198+
199+ if ( ! this . initialFilter || this . initialFilter ( record ) ) {
200+ initialFiles . set ( initialImport . path , record ) ;
201+ }
202+
203+ if ( ! initialImport . external ) {
204+ files . push ( initialImport . path ) ;
205+ }
163206 }
164207 }
165208 }
0 commit comments