@@ -50,13 +50,58 @@ class ApplicationBuildError extends Error {
5050 this . name = 'ApplicationBuildError' ;
5151 }
5252}
53+ const LATEST_BUILD_FILES_TOKEN = 'angularLatestBuildFiles' ;
54+ class AngularAssetsMiddleware {
55+ serveFile ;
56+ latestBuildFiles ;
57+ static $inject = [ 'serveFile' , LATEST_BUILD_FILES_TOKEN ] ;
58+ static NAME = 'angular-test-assets' ;
59+ constructor ( serveFile , latestBuildFiles ) {
60+ this . serveFile = serveFile ;
61+ this . latestBuildFiles = latestBuildFiles ;
62+ }
63+ handle ( req , res , next ) {
64+ let err = null ;
65+ try {
66+ const url = new URL ( `http://${ req . headers [ 'host' ] } ${ req . url } ` ) ;
67+ const file = this . latestBuildFiles . files [ url . pathname . slice ( 1 ) ] ;
68+ if ( file ?. origin === 'disk' ) {
69+ this . serveFile ( file . inputPath , undefined , res ) ;
70+ return ;
71+ }
72+ else if ( file ?. origin === 'memory' ) {
73+ // Include pathname to help with Content-Type headers.
74+ this . serveFile ( `/unused/${ url . pathname } ` , undefined , res , undefined , file . contents , true ) ;
75+ return ;
76+ }
77+ }
78+ catch ( e ) {
79+ err = e ;
80+ }
81+ next ( err ) ;
82+ }
83+ static createPlugin ( initialFiles ) {
84+ return {
85+ [ LATEST_BUILD_FILES_TOKEN ] : [ 'value' , { files : { ...initialFiles . files } } ] ,
86+ [ `middleware:${ AngularAssetsMiddleware . NAME } ` ] : [
87+ 'factory' ,
88+ Object . assign ( ( ...args ) => {
89+ const inst = new AngularAssetsMiddleware ( ...args ) ;
90+ return inst . handle . bind ( inst ) ;
91+ } , AngularAssetsMiddleware ) ,
92+ ] ,
93+ } ;
94+ }
95+ }
5396function injectKarmaReporter ( context , buildOptions , buildIterator , karmaConfig , subscriber ) {
5497 const reporterName = 'angular-progress-notifier' ;
5598 class ProgressNotifierReporter {
5699 emitter ;
57- static $inject = [ 'emitter' ] ;
58- constructor ( emitter ) {
100+ latestBuildFiles ;
101+ static $inject = [ 'emitter' , LATEST_BUILD_FILES_TOKEN ] ;
102+ constructor ( emitter , latestBuildFiles ) {
59103 this . emitter = emitter ;
104+ this . latestBuildFiles = latestBuildFiles ;
60105 this . startWatchingBuild ( ) ;
61106 }
62107 startWatchingBuild ( ) {
@@ -74,6 +119,15 @@ function injectKarmaReporter(context, buildOptions, buildIterator, karmaConfig,
74119 }
75120 else if ( buildOutput . kind === private_1 . ResultKind . Incremental ||
76121 buildOutput . kind === private_1 . ResultKind . Full ) {
122+ if ( buildOutput . kind === private_1 . ResultKind . Full ) {
123+ this . latestBuildFiles . files = buildOutput . files ;
124+ }
125+ else {
126+ this . latestBuildFiles . files = {
127+ ...this . latestBuildFiles . files ,
128+ ...buildOutput . files ,
129+ } ;
130+ }
77131 await writeTestFiles ( buildOutput . files , buildOptions . outputPath ) ;
78132 this . emitter . refreshFiles ( ) ;
79133 }
@@ -167,6 +221,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
167221 ? createInstrumentationFilter ( projectSourceRoot , getInstrumentationExcludedPaths ( context . workspaceRoot , options . codeCoverageExclude ?? [ ] ) )
168222 : undefined ;
169223 const buildOptions = {
224+ assets : options . assets ,
170225 entryPoints,
171226 tsConfig : options . tsConfig ,
172227 outputPath,
@@ -224,18 +279,23 @@ async function initializeApplication(options, context, karmaOptions, transforms
224279 // Remove the webpack plugin/framework:
225280 // Alternative would be to make the Karma plugin "smart" but that's a tall order
226281 // with managing unneeded imports etc..
227- const pluginLengthBefore = ( parsedKarmaConfig . plugins ?? [ ] ) . length ;
228- parsedKarmaConfig . plugins = ( parsedKarmaConfig . plugins ?? [ ] ) . filter ( ( plugin ) => {
282+ parsedKarmaConfig . plugins ??= [ ] ;
283+ const pluginLengthBefore = parsedKarmaConfig . plugins . length ;
284+ parsedKarmaConfig . plugins = parsedKarmaConfig . plugins . filter ( ( plugin ) => {
229285 if ( typeof plugin === 'string' ) {
230286 return plugin !== 'framework:@angular-devkit/build-angular' ;
231287 }
232288 return ! plugin [ 'framework:@angular-devkit/build-angular' ] ;
233289 } ) ;
234- parsedKarmaConfig . frameworks = parsedKarmaConfig . frameworks ?. filter ( ( framework ) => framework !== '@angular-devkit/build-angular' ) ;
235- const pluginLengthAfter = ( parsedKarmaConfig . plugins ?? [ ] ) . length ;
290+ parsedKarmaConfig . frameworks ??= [ ] ;
291+ parsedKarmaConfig . frameworks = parsedKarmaConfig . frameworks . filter ( ( framework ) => framework !== '@angular-devkit/build-angular' ) ;
292+ const pluginLengthAfter = parsedKarmaConfig . plugins . length ;
236293 if ( pluginLengthBefore !== pluginLengthAfter ) {
237294 context . logger . warn ( `Ignoring framework "@angular-devkit/build-angular" from karma config file because it's not compatible with the application builder.` ) ;
238295 }
296+ parsedKarmaConfig . plugins . push ( AngularAssetsMiddleware . createPlugin ( buildOutput ) ) ;
297+ parsedKarmaConfig . middleware ??= [ ] ;
298+ parsedKarmaConfig . middleware . push ( AngularAssetsMiddleware . NAME ) ;
239299 // When using code-coverage, auto-add karma-coverage.
240300 // This was done as part of the karma plugin for webpack.
241301 if ( options . codeCoverage &&
0 commit comments