@@ -50,7 +50,7 @@ class ApplicationBuildError extends Error {
5050 this . name = 'ApplicationBuildError' ;
5151 }
5252}
53- function injectKarmaReporter ( context , buildOptions , karmaConfig , subscriber ) {
53+ function injectKarmaReporter ( context , buildOptions , buildIterator , karmaConfig , subscriber ) {
5454 const reporterName = 'angular-progress-notifier' ;
5555 class ProgressNotifierReporter {
5656 emitter ;
@@ -61,10 +61,14 @@ function injectKarmaReporter(context, buildOptions, karmaConfig, subscriber) {
6161 }
6262 startWatchingBuild ( ) {
6363 void ( async ( ) => {
64- for await ( const buildOutput of ( 0 , private_1 . buildApplicationInternal ) ( {
65- ...buildOptions ,
66- watch : true ,
67- } , context ) ) {
64+ // This is effectively "for await of but skip what's already consumed".
65+ let isDone = false ; // to mark the loop condition as "not constant".
66+ while ( ! isDone ) {
67+ const { done, value : buildOutput } = await buildIterator . next ( ) ;
68+ if ( done ) {
69+ isDone = true ;
70+ break ;
71+ }
6872 if ( buildOutput . kind === private_1 . ResultKind . Failure ) {
6973 subscriber . next ( { success : false , message : 'Build failed' } ) ;
7074 }
@@ -96,11 +100,11 @@ function injectKarmaReporter(context, buildOptions, karmaConfig, subscriber) {
96100 } ) ;
97101}
98102function execute ( options , context , karmaOptions , transforms = { } ) {
99- return ( 0 , rxjs_1 . from ) ( initializeApplication ( options , context , karmaOptions , transforms ) ) . pipe ( ( 0 , rxjs_1 . switchMap ) ( ( [ karma , karmaConfig , buildOptions ] ) => new rxjs_1 . Observable ( ( subscriber ) => {
103+ return ( 0 , rxjs_1 . from ) ( initializeApplication ( options , context , karmaOptions , transforms ) ) . pipe ( ( 0 , rxjs_1 . switchMap ) ( ( [ karma , karmaConfig , buildOptions , buildIterator ] ) => new rxjs_1 . Observable ( ( subscriber ) => {
100104 // If `--watch` is explicitly enabled or if we are keeping the Karma
101105 // process running, we should hook Karma into the build.
102- if ( options . watch ?? ! karmaConfig . singleRun ) {
103- injectKarmaReporter ( context , buildOptions , karmaConfig , subscriber ) ;
106+ if ( buildIterator ) {
107+ injectKarmaReporter ( context , buildOptions , buildIterator , karmaConfig , subscriber ) ;
104108 }
105109 // Complete the observable once the Karma server returns.
106110 const karmaServer = new karma . Server ( karmaConfig , ( exitCode ) => {
@@ -179,9 +183,10 @@ async function initializeApplication(options, context, karmaOptions, transforms
179183 styles : options . styles ,
180184 polyfills : normalizePolyfills ( options . polyfills ) ,
181185 webWorkerTsConfig : options . webWorkerTsConfig ,
186+ watch : options . watch ?? ! karmaOptions . singleRun ,
182187 } ;
183188 // Build tests with `application` builder, using test files as entry points.
184- const buildOutput = await first ( ( 0 , private_1 . buildApplicationInternal ) ( buildOptions , context ) ) ;
189+ const [ buildOutput , buildIterator ] = await first ( ( 0 , private_1 . buildApplicationInternal ) ( buildOptions , context ) , { cancel : ! buildOptions . watch } ) ;
185190 if ( buildOutput . kind === private_1 . ResultKind . Failure ) {
186191 throw new ApplicationBuildError ( 'Build failed' ) ;
187192 }
@@ -193,22 +198,27 @@ async function initializeApplication(options, context, karmaOptions, transforms
193198 karmaOptions . files ??= [ ] ;
194199 karmaOptions . files . push (
195200 // Serve polyfills first.
196- { pattern : `${ outputPath } /polyfills.js` , type : 'module' } ,
201+ { pattern : `${ outputPath } /polyfills.js` , type : 'module' , watched : false } ,
197202 // Serve global setup script.
198- { pattern : `${ outputPath } /${ mainName } .js` , type : 'module' } ,
203+ { pattern : `${ outputPath } /${ mainName } .js` , type : 'module' , watched : false } ,
199204 // Serve all source maps.
200- { pattern : `${ outputPath } /*.map` , included : false } ) ;
205+ { pattern : `${ outputPath } /*.map` , included : false , watched : false } ) ;
201206 if ( hasChunkOrWorkerFiles ( buildOutput . files ) ) {
202207 karmaOptions . files . push (
203208 // Allow loading of chunk-* files but don't include them all on load.
204- { pattern : `${ outputPath } /{chunk,worker}-*.js` , type : 'module' , included : false } ) ;
209+ {
210+ pattern : `${ outputPath } /{chunk,worker}-*.js` ,
211+ type : 'module' ,
212+ included : false ,
213+ watched : false ,
214+ } ) ;
205215 }
206216 karmaOptions . files . push (
207217 // Serve remaining JS on page load, these are the test entrypoints.
208- { pattern : `${ outputPath } /*.js` , type : 'module' } ) ;
218+ { pattern : `${ outputPath } /*.js` , type : 'module' , watched : false } ) ;
209219 if ( options . styles ?. length ) {
210220 // Serve CSS outputs on page load, these are the global styles.
211- karmaOptions . files . push ( { pattern : `${ outputPath } /*.css` , type : 'css' } ) ;
221+ karmaOptions . files . push ( { pattern : `${ outputPath } /*.css` , type : 'css' , watched : false } ) ;
212222 }
213223 const parsedKarmaConfig = await karma . config . parseConfig ( options . karmaConfig && path . resolve ( context . workspaceRoot , options . karmaConfig ) , transforms . karmaOptions ? transforms . karmaOptions ( karmaOptions ) : karmaOptions , { promiseConfig : true , throwErrors : true } ) ;
214224 // Remove the webpack plugin/framework:
@@ -232,7 +242,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
232242 ! parsedKarmaConfig . reporters ?. some ( ( r ) => r === 'coverage' || r === 'coverage-istanbul' ) ) {
233243 parsedKarmaConfig . reporters = ( parsedKarmaConfig . reporters ?? [ ] ) . concat ( [ 'coverage' ] ) ;
234244 }
235- return [ karma , parsedKarmaConfig , buildOptions ] ;
245+ return [ karma , parsedKarmaConfig , buildOptions , buildIterator ] ;
236246}
237247function hasChunkOrWorkerFiles ( files ) {
238248 return Object . keys ( files ) . some ( ( filename ) => {
@@ -264,9 +274,17 @@ async function writeTestFiles(files, testDir) {
264274 } ) ;
265275}
266276/** Returns the first item yielded by the given generator and cancels the execution. */
267- async function first ( generator ) {
277+ async function first ( generator , { cancel } ) {
278+ if ( ! cancel ) {
279+ const iterator = generator [ Symbol . asyncIterator ] ( ) ;
280+ const firstValue = await iterator . next ( ) ;
281+ if ( firstValue . done ) {
282+ throw new Error ( 'Expected generator to emit at least once.' ) ;
283+ }
284+ return [ firstValue . value , iterator ] ;
285+ }
268286 for await ( const value of generator ) {
269- return value ;
287+ return [ value , null ] ;
270288 }
271289 throw new Error ( 'Expected generator to emit at least once.' ) ;
272290}
0 commit comments