@@ -50,13 +50,58 @@ class ApplicationBuildError extends Error {
50
50
this . name = 'ApplicationBuildError' ;
51
51
}
52
52
}
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
+ }
53
96
function injectKarmaReporter ( context , buildOptions , buildIterator , karmaConfig , subscriber ) {
54
97
const reporterName = 'angular-progress-notifier' ;
55
98
class ProgressNotifierReporter {
56
99
emitter ;
57
- static $inject = [ 'emitter' ] ;
58
- constructor ( emitter ) {
100
+ latestBuildFiles ;
101
+ static $inject = [ 'emitter' , LATEST_BUILD_FILES_TOKEN ] ;
102
+ constructor ( emitter , latestBuildFiles ) {
59
103
this . emitter = emitter ;
104
+ this . latestBuildFiles = latestBuildFiles ;
60
105
this . startWatchingBuild ( ) ;
61
106
}
62
107
startWatchingBuild ( ) {
@@ -74,6 +119,15 @@ function injectKarmaReporter(context, buildOptions, buildIterator, karmaConfig,
74
119
}
75
120
else if ( buildOutput . kind === private_1 . ResultKind . Incremental ||
76
121
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
+ }
77
131
await writeTestFiles ( buildOutput . files , buildOptions . outputPath ) ;
78
132
this . emitter . refreshFiles ( ) ;
79
133
}
@@ -167,6 +221,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
167
221
? createInstrumentationFilter ( projectSourceRoot , getInstrumentationExcludedPaths ( context . workspaceRoot , options . codeCoverageExclude ?? [ ] ) )
168
222
: undefined ;
169
223
const buildOptions = {
224
+ assets : options . assets ,
170
225
entryPoints,
171
226
tsConfig : options . tsConfig ,
172
227
outputPath,
@@ -224,18 +279,23 @@ async function initializeApplication(options, context, karmaOptions, transforms
224
279
// Remove the webpack plugin/framework:
225
280
// Alternative would be to make the Karma plugin "smart" but that's a tall order
226
281
// 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 ) => {
229
285
if ( typeof plugin === 'string' ) {
230
286
return plugin !== 'framework:@angular-devkit/build-angular' ;
231
287
}
232
288
return ! plugin [ 'framework:@angular-devkit/build-angular' ] ;
233
289
} ) ;
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 ;
236
293
if ( pluginLengthBefore !== pluginLengthAfter ) {
237
294
context . logger . warn ( `Ignoring framework "@angular-devkit/build-angular" from karma config file because it's not compatible with the application builder.` ) ;
238
295
}
296
+ parsedKarmaConfig . plugins . push ( AngularAssetsMiddleware . createPlugin ( buildOutput ) ) ;
297
+ parsedKarmaConfig . middleware ??= [ ] ;
298
+ parsedKarmaConfig . middleware . push ( AngularAssetsMiddleware . NAME ) ;
239
299
// When using code-coverage, auto-add karma-coverage.
240
300
// This was done as part of the karma plugin for webpack.
241
301
if ( options . codeCoverage &&
0 commit comments