@@ -20,7 +20,6 @@ import {
20
20
formatMessages ,
21
21
} from 'esbuild' ;
22
22
import { basename , extname , relative } from 'node:path' ;
23
- import { FileInfo } from '../../utils/index-file/augment-index-html' ;
24
23
25
24
export type BundleContextResult =
26
25
| { errors : Message [ ] ; warnings : Message [ ] }
@@ -29,7 +28,7 @@ export type BundleContextResult =
29
28
warnings : Message [ ] ;
30
29
metafile : Metafile ;
31
30
outputFiles : OutputFile [ ] ;
32
- initialFiles : FileInfo [ ] ;
31
+ initialFiles : Map < string , InitialFileRecord > ;
33
32
} ;
34
33
35
34
/**
@@ -41,11 +40,23 @@ export function isEsBuildFailure(value: unknown): value is BuildFailure {
41
40
return ! ! value && typeof value === 'object' && 'errors' in value && 'warnings' in value ;
42
41
}
43
42
43
+ export interface InitialFileRecord {
44
+ entrypoint : boolean ;
45
+ name ?: string ;
46
+ type : 'script' | 'style' ;
47
+ external ?: boolean ;
48
+ }
49
+
44
50
export class BundlerContext {
45
51
#esbuildContext?: BuildContext < { metafile : true ; write : false } > ;
46
52
#esbuildOptions: BuildOptions & { metafile : true ; write : false } ;
47
53
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
+ ) {
49
60
this . #esbuildOptions = {
50
61
...options ,
51
62
metafile : true ,
@@ -64,7 +75,7 @@ export class BundlerContext {
64
75
let errors : Message [ ] | undefined ;
65
76
const warnings : Message [ ] = [ ] ;
66
77
const metafile : Metafile = { inputs : { } , outputs : { } } ;
67
- const initialFiles = [ ] ;
78
+ const initialFiles = new Map < string , InitialFileRecord > ( ) ;
68
79
const outputFiles = [ ] ;
69
80
for ( const result of individualResults ) {
70
81
warnings . push ( ...result . warnings ) ;
@@ -80,7 +91,7 @@ export class BundlerContext {
80
91
metafile . outputs = { ...metafile . outputs , ...result . metafile . outputs } ;
81
92
}
82
93
83
- initialFiles . push ( ... result . initialFiles ) ;
94
+ result . initialFiles . forEach ( ( value , key ) => initialFiles . set ( key , value ) ) ;
84
95
outputFiles . push ( ...result . outputFiles ) ;
85
96
}
86
97
@@ -139,27 +150,59 @@ export class BundlerContext {
139
150
}
140
151
141
152
// Find all initial files
142
- const initialFiles : FileInfo [ ] = [ ] ;
153
+ const initialFiles = new Map < string , InitialFileRecord > ( ) ;
143
154
for ( const outputFile of result . outputFiles ) {
144
155
// Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot
145
156
const relativeFilePath = relative ( this . workspaceRoot , outputFile . path ) ;
146
- const entryPoint = result . metafile ? .outputs [ relativeFilePath ] ?. entryPoint ;
157
+ const entryPoint = result . metafile . outputs [ relativeFilePath ] ?. entryPoint ;
147
158
148
159
outputFile . path = relativeFilePath ;
149
160
150
161
if ( entryPoint ) {
151
162
// 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' ;
153
166
154
167
// Only entrypoints with an entry in the options are initial files.
155
168
// Dynamic imports also have an entryPoint value in the meta file.
156
169
if ( ( this . #esbuildOptions. entryPoints as Record < string , string > ) ?. [ name ] ) {
157
170
// An entryPoint value indicates an initial file
158
- initialFiles . push ( {
159
- file : outputFile . path ,
171
+ const record : InitialFileRecord = {
160
172
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
+ }
163
206
}
164
207
}
165
208
}
0 commit comments