@@ -90,13 +90,14 @@ function initializeNgccProcessor(
90
90
return { processor, errors, warnings } ;
91
91
}
92
92
93
- function hashContent ( content : string ) : Uint8Array {
94
- return createHash ( 'md5' ) . update ( content ) . digest ( ) ;
95
- }
96
-
97
93
const PLUGIN_NAME = 'angular-compiler' ;
98
94
const compilationFileEmitters = new WeakMap < Compilation , FileEmitterCollection > ( ) ;
99
95
96
+ interface FileEmitHistoryItem {
97
+ length : number ;
98
+ hash : Uint8Array ;
99
+ }
100
+
100
101
export class AngularWebpackPlugin {
101
102
private readonly pluginOptions : AngularWebpackPluginOptions ;
102
103
private compilerCliModule ?: typeof import ( '@angular/compiler-cli' ) ;
@@ -105,10 +106,11 @@ export class AngularWebpackPlugin {
105
106
private ngtscNextProgram ?: NgtscProgram ;
106
107
private builder ?: ts . EmitAndSemanticDiagnosticsBuilderProgram ;
107
108
private sourceFileCache ?: SourceFileCache ;
109
+ private webpackCache ?: ReturnType < Compilation [ 'getCache' ] > ;
108
110
private readonly fileDependencies = new Map < string , Set < string > > ( ) ;
109
111
private readonly requiredFilesToEmit = new Set < string > ( ) ;
110
112
private readonly requiredFilesToEmitCache = new Map < string , EmitFileResult | undefined > ( ) ;
111
- private readonly fileEmitHistory = new Map < string , { length : number ; hash : Uint8Array } > ( ) ;
113
+ private readonly fileEmitHistory = new Map < string , FileEmitHistoryItem > ( ) ;
112
114
113
115
constructor ( options : Partial < AngularWebpackPluginOptions > = { } ) {
114
116
this . pluginOptions = {
@@ -136,6 +138,7 @@ export class AngularWebpackPlugin {
136
138
return this . pluginOptions ;
137
139
}
138
140
141
+ // eslint-disable-next-line max-lines-per-function
139
142
apply ( compiler : Compiler ) : void {
140
143
const { NormalModuleReplacementPlugin, util } = compiler . webpack ;
141
144
@@ -177,9 +180,13 @@ export class AngularWebpackPlugin {
177
180
compiler . hooks . thisCompilation . tap ( PLUGIN_NAME , ( compilation ) => {
178
181
// Register plugin to ensure deterministic emit order in multi-plugin usage
179
182
const emitRegistration = this . registerWithCompilation ( compilation ) ;
180
-
181
183
this . watchMode = compiler . watchMode ;
182
184
185
+ // Initialize webpack cache
186
+ if ( ! this . webpackCache && compilation . options . cache ) {
187
+ this . webpackCache = compilation . getCache ( PLUGIN_NAME ) ;
188
+ }
189
+
183
190
// Initialize the resource loader if not already setup
184
191
if ( ! resourceLoader ) {
185
192
resourceLoader = new WebpackResourceLoader ( this . watchMode ) ;
@@ -377,7 +384,7 @@ export class AngularWebpackPlugin {
377
384
378
385
const filesToRebuild = new Set < string > ( ) ;
379
386
for ( const requiredFile of this . requiredFilesToEmit ) {
380
- const history = this . fileEmitHistory . get ( requiredFile ) ;
387
+ const history = await this . getFileEmitHistory ( requiredFile ) ;
381
388
if ( history ) {
382
389
const emitResult = await fileEmitter ( requiredFile ) ;
383
390
if (
@@ -706,12 +713,8 @@ export class AngularWebpackPlugin {
706
713
707
714
onAfterEmit ?.( sourceFile ) ;
708
715
709
- let hash ;
710
- if ( content !== undefined && this . watchMode ) {
711
- // Capture emit history info for Angular rebuild analysis
712
- hash = hashContent ( content ) ;
713
- this . fileEmitHistory . set ( filePath , { length : content . length , hash } ) ;
714
- }
716
+ // Capture emit history info for Angular rebuild analysis
717
+ const hash = content ? ( await this . addFileEmitHistory ( filePath , content ) ) . hash : undefined ;
715
718
716
719
const dependencies = [
717
720
...( this . fileDependencies . get ( filePath ) || [ ] ) ,
@@ -737,4 +740,33 @@ export class AngularWebpackPlugin {
737
740
this . compilerCliModule = await new Function ( `return import('@angular/compiler-cli');` ) ( ) ;
738
741
this . compilerNgccModule = await new Function ( `return import('@angular/compiler-cli/ngcc');` ) ( ) ;
739
742
}
743
+
744
+ private async addFileEmitHistory (
745
+ filePath : string ,
746
+ content : string ,
747
+ ) : Promise < FileEmitHistoryItem > {
748
+ const historyData : FileEmitHistoryItem = {
749
+ length : content . length ,
750
+ hash : createHash ( 'md5' ) . update ( content ) . digest ( ) ,
751
+ } ;
752
+
753
+ if ( this . webpackCache ) {
754
+ const history = await this . getFileEmitHistory ( filePath ) ;
755
+ if ( ! history || Buffer . compare ( history . hash , historyData . hash ) !== 0 ) {
756
+ // Hash doesn't match or item doesn't exist.
757
+ await this . webpackCache . storePromise ( filePath , null , historyData ) ;
758
+ }
759
+ } else if ( this . watchMode ) {
760
+ // The in memory file emit history is only required during watch mode.
761
+ this . fileEmitHistory . set ( filePath , historyData ) ;
762
+ }
763
+
764
+ return historyData ;
765
+ }
766
+
767
+ private async getFileEmitHistory ( filePath : string ) : Promise < FileEmitHistoryItem | undefined > {
768
+ return this . webpackCache
769
+ ? this . webpackCache . getPromise < FileEmitHistoryItem | undefined > ( filePath , null )
770
+ : this . fileEmitHistory . get ( filePath ) ;
771
+ }
740
772
}
0 commit comments