@@ -22,39 +22,39 @@ const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
22
22
interface CompilationOutput {
23
23
outputName : string ;
24
24
source : string ;
25
+ success : boolean ;
25
26
}
26
27
27
28
export class WebpackResourceLoader {
28
29
private _parentCompilation : any ;
29
- private _context = '' ;
30
30
private _fileDependencies = new Map < string , Set < string > > ( ) ;
31
31
private _reverseDependencies = new Map < string , Set < string > > ( ) ;
32
- private _cachedSources = new Map < string , string > ( ) ;
33
- private _cachedEvaluatedSources = new Map < string , RawSource > ( ) ;
34
32
35
- public changedFiles ?: Iterable < string > ;
33
+ private cache = new Map < string , string > ( ) ;
34
+ private modifiedResources = new Set < string > ( ) ;
36
35
37
- update ( parentCompilation : import ( 'webpack' ) . compilation . Compilation , changedFiles ?: Iterable < string > ) {
36
+ update (
37
+ parentCompilation : import ( 'webpack' ) . compilation . Compilation ,
38
+ changedFiles ?: Iterable < string > ,
39
+ ) {
38
40
this . _parentCompilation = parentCompilation ;
39
- this . _context = parentCompilation . context ;
40
41
41
- // Update changed file list
42
- this . changedFiles = changedFiles ;
42
+ // Update resource cache and modified resources
43
+ this . modifiedResources . clear ( ) ;
44
+ if ( changedFiles ) {
45
+ for ( const changedFile of changedFiles ) {
46
+ for ( const affectedResource of this . getAffectedResources ( changedFile ) ) {
47
+ this . cache . delete ( normalizePath ( affectedResource ) ) ;
48
+ this . modifiedResources . add ( affectedResource ) ;
49
+ }
50
+ }
51
+ } else {
52
+ this . cache . clear ( ) ;
53
+ }
43
54
}
44
55
45
56
getModifiedResourceFiles ( ) {
46
- const modifiedResources = new Set < string > ( ) ;
47
- if ( ! this . changedFiles ) {
48
- return modifiedResources ;
49
- }
50
-
51
- for ( const changedFile of this . changedFiles ) {
52
- this . getAffectedResources (
53
- changedFile ,
54
- ) . forEach ( ( affected : string ) => modifiedResources . add ( affected ) ) ;
55
- }
56
-
57
- return modifiedResources ;
57
+ return this . modifiedResources ;
58
58
}
59
59
60
60
getResourceDependencies ( filePath : string ) {
@@ -70,7 +70,6 @@ export class WebpackResourceLoader {
70
70
}
71
71
72
72
private async _compile ( filePath : string ) : Promise < CompilationOutput > {
73
-
74
73
if ( ! this . _parentCompilation ) {
75
74
throw new Error ( 'WebpackResourceLoader cannot be used without parentCompilation' ) ;
76
75
}
@@ -83,39 +82,25 @@ export class WebpackResourceLoader {
83
82
}
84
83
85
84
const outputOptions = { filename : filePath } ;
86
- const relativePath = path . relative ( this . _context || '' , filePath ) ;
85
+ const context = this . _parentCompilation . context ;
86
+ const relativePath = path . relative ( context || '' , filePath ) ;
87
87
const childCompiler = this . _parentCompilation . createChildCompiler ( relativePath , outputOptions ) ;
88
- childCompiler . context = this . _context ;
88
+ childCompiler . context = context ;
89
89
90
90
new NodeTemplatePlugin ( outputOptions ) . apply ( childCompiler ) ;
91
91
new NodeTargetPlugin ( ) . apply ( childCompiler ) ;
92
- new SingleEntryPlugin ( this . _context , filePath ) . apply ( childCompiler ) ;
92
+ new SingleEntryPlugin ( context , filePath ) . apply ( childCompiler ) ;
93
93
new LibraryTemplatePlugin ( 'resource' , 'var' ) . apply ( childCompiler ) ;
94
94
95
95
childCompiler . hooks . thisCompilation . tap ( 'ngtools-webpack' , ( compilation : any ) => {
96
- compilation . hooks . additionalAssets . tapAsync ( 'ngtools-webpack' ,
97
- ( callback : ( err ?: Error ) => void ) => {
98
- if ( this . _cachedEvaluatedSources . has ( compilation . fullHash ) ) {
99
- const cachedEvaluatedSource = this . _cachedEvaluatedSources . get ( compilation . fullHash ) ;
100
- compilation . assets [ filePath ] = cachedEvaluatedSource ;
101
- callback ( ) ;
102
-
96
+ compilation . hooks . additionalAssets . tapPromise ( 'ngtools-webpack' , async ( ) => {
97
+ const asset = compilation . assets [ filePath ] ;
98
+ if ( ! asset ) {
103
99
return ;
104
100
}
105
101
106
- const asset = compilation . assets [ filePath ] ;
107
- if ( asset ) {
108
- this . _evaluate ( { outputName : filePath , source : asset . source ( ) } )
109
- . then ( output => {
110
- const evaluatedSource = new RawSource ( output ) ;
111
- this . _cachedEvaluatedSources . set ( compilation . fullHash , evaluatedSource ) ;
112
- compilation . assets [ filePath ] = evaluatedSource ;
113
- callback ( ) ;
114
- } )
115
- . catch ( err => callback ( err ) ) ;
116
- } else {
117
- callback ( ) ;
118
- }
102
+ const output = await this . _evaluate ( filePath , asset . source ( ) ) ;
103
+ compilation . assets [ filePath ] = new RawSource ( output ) ;
119
104
} ) ;
120
105
} ) ;
121
106
@@ -139,13 +124,13 @@ export class WebpackResourceLoader {
139
124
this . _parentCompilation . errors . push ( ...errors ) ;
140
125
}
141
126
142
- Object . keys ( childCompilation . assets ) . forEach ( assetName => {
127
+ Object . keys ( childCompilation . assets ) . forEach ( ( assetName ) => {
143
128
// Add all new assets to the parent compilation, with the exception of
144
129
// the file we're loading and its sourcemap.
145
130
if (
146
- assetName !== filePath
147
- && assetName !== `${ filePath } .map`
148
- && this . _parentCompilation . assets [ assetName ] == undefined
131
+ assetName !== filePath &&
132
+ assetName !== `${ filePath } .map` &&
133
+ this . _parentCompilation . assets [ assetName ] == undefined
149
134
) {
150
135
this . _parentCompilation . assets [ assetName ] = childCompilation . assets [ assetName ] ;
151
136
}
@@ -163,34 +148,40 @@ export class WebpackResourceLoader {
163
148
}
164
149
}
165
150
166
- const compilationHash = childCompilation . fullHash ;
167
- const maybeSource = this . _cachedSources . get ( compilationHash ) ;
168
- if ( maybeSource ) {
169
- return { outputName : filePath , source : maybeSource } ;
170
- } else {
171
- const source = childCompilation . assets [ filePath ] . source ( ) ;
172
- this . _cachedSources . set ( compilationHash , source ) ;
151
+ const finalOutput = childCompilation . assets [ filePath ] ?. source ( ) ;
173
152
174
- return { outputName : filePath , source } ;
175
- }
153
+ return { outputName : filePath , source : finalOutput ?? '' , success : ! errors ?. length } ;
176
154
}
177
155
178
- private async _evaluate ( { outputName , source } : CompilationOutput ) : Promise < string > {
179
- // Evaluate code
180
- const context : { resource ?: string | { default ?: string } } = { } ;
181
- vm . runInNewContext ( source , context , { filename : outputName } ) ;
156
+ private async _evaluate ( filename : string , source : string ) : Promise < string > {
157
+ // Evaluate code
158
+ const context : { resource ?: string | { default ?: string } } = { } ;
159
+ vm . runInNewContext ( source , context , { filename } ) ;
182
160
183
- if ( typeof context . resource === 'string' ) {
184
- return context . resource ;
185
- } else if ( typeof context . resource ?. default === 'string' ) {
186
- return context . resource . default ;
187
- }
161
+ if ( typeof context . resource === 'string' ) {
162
+ return context . resource ;
163
+ } else if ( typeof context . resource ?. default === 'string' ) {
164
+ return context . resource . default ;
165
+ }
188
166
189
- throw new Error ( `The loader "${ outputName } " didn't return a string.` ) ;
167
+ throw new Error ( `The loader "${ filename } " didn't return a string.` ) ;
190
168
}
191
169
192
- get ( filePath : string ) : Promise < string > {
193
- return this . _compile ( filePath )
194
- . then ( ( result : CompilationOutput ) => result . source ) ;
170
+ async get ( filePath : string ) : Promise < string > {
171
+ const normalizedFile = normalizePath ( filePath ) ;
172
+ let data = this . cache . get ( normalizedFile ) ;
173
+
174
+ if ( data === undefined ) {
175
+ // cache miss so compile resource
176
+ const compilationResult = await this . _compile ( filePath ) ;
177
+ data = compilationResult . source ;
178
+
179
+ // Only cache if compilation was successful
180
+ if ( compilationResult . success ) {
181
+ this . cache . set ( normalizedFile , data ) ;
182
+ }
183
+ }
184
+
185
+ return data ;
195
186
}
196
187
}
0 commit comments