55 * Use of this source code is governed by an MIT-style license that can be
66 * found in the LICENSE file at https://angular.io/license
77 */
8- // TODO: fix typings.
9- // tslint:disable-next-line:no-global-tslint-disable
10- // tslint:disable:no-any
11- import * as path from 'path' ;
128import * as vm from 'vm' ;
9+ import { Compiler , compilation } from 'webpack' ;
1310import { RawSource } from 'webpack-sources' ;
1411import { normalizePath } from './ivy/paths' ;
1512
@@ -18,26 +15,43 @@ const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
1815const LibraryTemplatePlugin = require ( 'webpack/lib/LibraryTemplatePlugin' ) ;
1916const SingleEntryPlugin = require ( 'webpack/lib/SingleEntryPlugin' ) ;
2017
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+ } ;
2135
2236interface CompilationOutput {
23- outputName : string ;
24- source : string ;
37+ content : string ;
38+ map ? : string ;
2539 success : boolean ;
2640}
2741
2842export class WebpackResourceLoader {
29- private _parentCompilation : any ;
43+ private _parentCompilation ?: WebpackCompilation ;
3044 private _fileDependencies = new Map < string , Set < string > > ( ) ;
3145 private _reverseDependencies = new Map < string , Set < string > > ( ) ;
3246
33- private cache = new Map < string , string > ( ) ;
47+ private cache = new Map < string , CompilationOutput > ( ) ;
3448 private modifiedResources = new Set < string > ( ) ;
3549
3650 update (
37- parentCompilation : import ( 'webpack' ) . compilation . Compilation ,
51+ parentCompilation : compilation . Compilation ,
3852 changedFiles ?: Iterable < string > ,
3953 ) {
40- this . _parentCompilation = parentCompilation ;
54+ this . _parentCompilation = parentCompilation as WebpackCompilation ;
4155
4256 // Update resource cache and modified resources
4357 this . modifiedResources . clear ( ) ;
@@ -82,28 +96,32 @@ export class WebpackResourceLoader {
8296 }
8397
8498 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' , ( ) => {
97113 const asset = compilation . assets [ filePath ] ;
98114 if ( ! asset ) {
99115 return ;
100116 }
101117
102118 try {
103- const output = this . _evaluate ( filePath , asset . source ( ) ) ;
119+ const output = this . _evaluate ( filePath , asset . source ( ) . toString ( ) ) ;
104120
105121 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 ;
107125 }
108126 } catch ( error ) {
109127 // Use compilation errors, as otherwise webpack will choke
@@ -112,53 +130,47 @@ export class WebpackResourceLoader {
112130 } ) ;
113131 } ) ;
114132
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' ] ;
124141 } ) ;
125142
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 ) ;
134147
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' ) ) ;
146151
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+ }
158154
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+ }
160166
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+ } ) ;
162174 }
163175
164176 private _evaluate ( filename : string , source : string ) : string | null {
@@ -183,19 +195,18 @@ export class WebpackResourceLoader {
183195
184196 async get ( filePath : string ) : Promise < string > {
185197 const normalizedFile = normalizePath ( filePath ) ;
186- let data = this . cache . get ( normalizedFile ) ;
198+ let compilationResult = this . cache . get ( normalizedFile ) ;
187199
188- if ( data === undefined ) {
200+ if ( compilationResult === undefined ) {
189201 // cache miss so compile resource
190- const compilationResult = await this . _compile ( filePath ) ;
191- data = compilationResult . source ;
202+ compilationResult = await this . _compile ( filePath ) ;
192203
193204 // Only cache if compilation was successful
194205 if ( compilationResult . success ) {
195- this . cache . set ( normalizedFile , data ) ;
206+ this . cache . set ( normalizedFile , compilationResult ) ;
196207 }
197208 }
198209
199- return data ;
210+ return compilationResult . content ;
200211 }
201212}
0 commit comments