5
5
* Use of this source code is governed by an MIT-style license that can be
6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
- // TODO: fix typings.
9
- // tslint:disable-next-line:no-global-tslint-disable
10
- // tslint:disable:no-any
11
- import * as path from 'path' ;
12
8
import * as vm from 'vm' ;
9
+ import { Compiler , compilation } from 'webpack' ;
13
10
import { RawSource } from 'webpack-sources' ;
14
11
import { normalizePath } from './ivy/paths' ;
15
12
@@ -18,26 +15,43 @@ const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
18
15
const LibraryTemplatePlugin = require ( 'webpack/lib/LibraryTemplatePlugin' ) ;
19
16
const SingleEntryPlugin = require ( 'webpack/lib/SingleEntryPlugin' ) ;
20
17
18
+ type WebpackCompilation = compilation . Compilation & {
19
+ createChildCompiler (
20
+ name : string ,
21
+ outputOptions : { } ,
22
+ plugins : ( ( compiler : Compiler ) => void ) [ ] ,
23
+ ) : WebpackCompiler ;
24
+ } ;
25
+
26
+ type WebpackCompiler = Compiler & {
27
+ runAsChild (
28
+ callback : (
29
+ error ?: Error ,
30
+ entries ?: unknown ,
31
+ compilation ?: compilation . Compilation ,
32
+ ) => void ,
33
+ ) : void ;
34
+ } ;
21
35
22
36
interface CompilationOutput {
23
- outputName : string ;
24
- source : string ;
37
+ content : string ;
38
+ map ? : string ;
25
39
success : boolean ;
26
40
}
27
41
28
42
export class WebpackResourceLoader {
29
- private _parentCompilation : any ;
43
+ private _parentCompilation ?: WebpackCompilation ;
30
44
private _fileDependencies = new Map < string , Set < string > > ( ) ;
31
45
private _reverseDependencies = new Map < string , Set < string > > ( ) ;
32
46
33
- private cache = new Map < string , string > ( ) ;
47
+ private cache = new Map < string , CompilationOutput > ( ) ;
34
48
private modifiedResources = new Set < string > ( ) ;
35
49
36
50
update (
37
- parentCompilation : import ( 'webpack' ) . compilation . Compilation ,
51
+ parentCompilation : compilation . Compilation ,
38
52
changedFiles ?: Iterable < string > ,
39
53
) {
40
- this . _parentCompilation = parentCompilation ;
54
+ this . _parentCompilation = parentCompilation as WebpackCompilation ;
41
55
42
56
// Update resource cache and modified resources
43
57
this . modifiedResources . clear ( ) ;
@@ -82,28 +96,32 @@ export class WebpackResourceLoader {
82
96
}
83
97
84
98
const outputOptions = { filename : filePath } ;
85
- const context = this . _parentCompilation . context ;
86
- const relativePath = path . relative ( context || '' , filePath ) ;
87
- const childCompiler = this . _parentCompilation . createChildCompiler ( relativePath , outputOptions ) ;
88
- childCompiler . context = context ;
89
-
90
- new NodeTemplatePlugin ( outputOptions ) . apply ( childCompiler ) ;
91
- new NodeTargetPlugin ( ) . apply ( childCompiler ) ;
92
- new SingleEntryPlugin ( context , filePath ) . apply ( childCompiler ) ;
93
- new LibraryTemplatePlugin ( 'resource' , 'var' ) . apply ( childCompiler ) ;
94
-
95
- childCompiler . hooks . thisCompilation . tap ( 'ngtools-webpack' , ( compilation : any ) => {
96
- compilation . hooks . additionalAssets . tap ( 'ngtools-webpack' , ( ) => {
99
+ const context = this . _parentCompilation . compiler . context ;
100
+ const childCompiler = this . _parentCompilation . createChildCompiler (
101
+ 'angular-compiler:resource' ,
102
+ outputOptions ,
103
+ [
104
+ new NodeTemplatePlugin ( outputOptions ) ,
105
+ new NodeTargetPlugin ( ) ,
106
+ new SingleEntryPlugin ( context , filePath , 'resource' ) ,
107
+ new LibraryTemplatePlugin ( 'resource' , 'var' ) ,
108
+ ] ,
109
+ ) ;
110
+
111
+ childCompiler . hooks . thisCompilation . tap ( 'angular-compiler' , ( compilation ) => {
112
+ compilation . hooks . additionalAssets . tap ( 'angular-compiler' , ( ) => {
97
113
const asset = compilation . assets [ filePath ] ;
98
114
if ( ! asset ) {
99
115
return ;
100
116
}
101
117
102
118
try {
103
- const output = this . _evaluate ( filePath , asset . source ( ) ) ;
119
+ const output = this . _evaluate ( filePath , asset . source ( ) . toString ( ) ) ;
104
120
105
121
if ( typeof output === 'string' ) {
106
- compilation . assets [ filePath ] = new RawSource ( output ) ;
122
+ // `webpack-sources` package has incomplete typings
123
+ // tslint:disable-next-line: no-any
124
+ compilation . assets [ filePath ] = new RawSource ( output ) as any ;
107
125
}
108
126
} catch ( error ) {
109
127
// Use compilation errors, as otherwise webpack will choke
@@ -112,53 +130,47 @@ export class WebpackResourceLoader {
112
130
} ) ;
113
131
} ) ;
114
132
115
- // Compile and return a promise
116
- const childCompilation = await new Promise < any > ( ( resolve , reject ) => {
117
- childCompiler . compile ( ( err : Error , childCompilation : any ) => {
118
- if ( err ) {
119
- reject ( err ) ;
120
- } else {
121
- resolve ( childCompilation ) ;
122
- }
123
- } ) ;
133
+ let finalContent : string | undefined ;
134
+ let finalMap : string | undefined ;
135
+ childCompiler . hooks . afterCompile . tap ( 'angular-compiler' , ( childCompilation ) => {
136
+ finalContent = childCompilation . assets [ filePath ] ?. source ( ) . toString ( ) ;
137
+ finalMap = childCompilation . assets [ filePath + '.map' ] ?. source ( ) . toString ( ) ;
138
+
139
+ delete childCompilation . assets [ filePath ] ;
140
+ delete childCompilation . assets [ filePath + '.map' ] ;
124
141
} ) ;
125
142
126
- // Propagate warnings to parent compilation.
127
- const { warnings, errors } = childCompilation ;
128
- if ( warnings && warnings . length ) {
129
- this . _parentCompilation . warnings . push ( ...warnings ) ;
130
- }
131
- if ( errors && errors . length ) {
132
- this . _parentCompilation . errors . push ( ...errors ) ;
133
- }
143
+ return new Promise < CompilationOutput > ( ( resolve , reject ) => {
144
+ childCompiler . runAsChild ( ( error , _ , childCompilation ) => {
145
+ if ( error ) {
146
+ reject ( error ) ;
134
147
135
- Object . keys ( childCompilation . assets ) . forEach ( ( assetName ) => {
136
- // Add all new assets to the parent compilation, with the exception of
137
- // the file we're loading and its sourcemap.
138
- if (
139
- assetName !== filePath &&
140
- assetName !== `${ filePath } .map` &&
141
- this . _parentCompilation . assets [ assetName ] == undefined
142
- ) {
143
- this . _parentCompilation . assets [ assetName ] = childCompilation . assets [ assetName ] ;
144
- }
145
- } ) ;
148
+ return ;
149
+ } else if ( ! childCompilation ) {
150
+ reject ( new Error ( 'Unknown child compilation error' ) ) ;
146
151
147
- // Save the dependencies for this resource.
148
- this . _fileDependencies . set ( filePath , new Set ( childCompilation . fileDependencies ) ) ;
149
- for ( const file of childCompilation . fileDependencies ) {
150
- const resolvedFile = normalizePath ( file ) ;
151
- const entry = this . _reverseDependencies . get ( resolvedFile ) ;
152
- if ( entry ) {
153
- entry . add ( filePath ) ;
154
- } else {
155
- this . _reverseDependencies . set ( resolvedFile , new Set ( [ filePath ] ) ) ;
156
- }
157
- }
152
+ return ;
153
+ }
158
154
159
- const finalOutput = childCompilation . assets [ filePath ] ?. source ( ) ;
155
+ // Save the dependencies for this resource.
156
+ this . _fileDependencies . set ( filePath , new Set ( childCompilation . fileDependencies ) ) ;
157
+ for ( const file of childCompilation . fileDependencies ) {
158
+ const resolvedFile = normalizePath ( file ) ;
159
+ const entry = this . _reverseDependencies . get ( resolvedFile ) ;
160
+ if ( entry ) {
161
+ entry . add ( filePath ) ;
162
+ } else {
163
+ this . _reverseDependencies . set ( resolvedFile , new Set ( [ filePath ] ) ) ;
164
+ }
165
+ }
160
166
161
- return { outputName : filePath , source : finalOutput ?? '' , success : ! errors ?. length } ;
167
+ resolve ( {
168
+ content : finalContent ?? '' ,
169
+ map : finalMap ,
170
+ success : childCompilation . errors ?. length === 0 ,
171
+ } ) ;
172
+ } ) ;
173
+ } ) ;
162
174
}
163
175
164
176
private _evaluate ( filename : string , source : string ) : string | null {
@@ -183,19 +195,18 @@ export class WebpackResourceLoader {
183
195
184
196
async get ( filePath : string ) : Promise < string > {
185
197
const normalizedFile = normalizePath ( filePath ) ;
186
- let data = this . cache . get ( normalizedFile ) ;
198
+ let compilationResult = this . cache . get ( normalizedFile ) ;
187
199
188
- if ( data === undefined ) {
200
+ if ( compilationResult === undefined ) {
189
201
// cache miss so compile resource
190
- const compilationResult = await this . _compile ( filePath ) ;
191
- data = compilationResult . source ;
202
+ compilationResult = await this . _compile ( filePath ) ;
192
203
193
204
// Only cache if compilation was successful
194
205
if ( compilationResult . success ) {
195
- this . cache . set ( normalizedFile , data ) ;
206
+ this . cache . set ( normalizedFile , compilationResult ) ;
196
207
}
197
208
}
198
209
199
- return data ;
210
+ return compilationResult . content ;
200
211
}
201
212
}
0 commit comments