7
7
*/
8
8
9
9
import { Logger , PathMappings , process as mainNgcc } from '@angular/compiler-cli/ngcc' ;
10
+ import { spawnSync } from 'child_process' ;
10
11
import { accessSync , constants , existsSync } from 'fs' ;
11
12
import * as path from 'path' ;
12
13
import * as ts from 'typescript' ;
@@ -49,6 +50,52 @@ export class NgccProcessor {
49
50
}
50
51
}
51
52
53
+ /** Process the entire node modules tree. */
54
+ process ( ) {
55
+ const timeLabel = 'NgccProcessor.process' ;
56
+ time ( timeLabel ) ;
57
+
58
+ const corePackage = this . tryResolvePackage ( '@angular/core' , this . _nodeModulesDirectory ) ;
59
+
60
+ // If the package.json is read only we should skip calling NGCC.
61
+ // With Bazel when running under sandbox the filesystem is read-only.
62
+ if ( corePackage && isReadOnlyFile ( corePackage ) ) {
63
+ timeEnd ( timeLabel ) ;
64
+
65
+ return ;
66
+ }
67
+
68
+ // We spawn instead of using the API because:
69
+ // - NGCC Async uses clustering which is problematic when used via the API which means
70
+ // that we cannot setup multiple cluster masters with different options.
71
+ // - We will not be able to have concurrent builds otherwise Ex: App-Shell,
72
+ // as NGCC will create a lock file for both builds and it will cause builds to fails.
73
+ const { status, error } = spawnSync (
74
+ process . execPath ,
75
+ [
76
+ require . resolve ( '@angular/compiler-cli/ngcc/main-ngcc.js' ) ,
77
+ '--source' , /** basePath */
78
+ this . _nodeModulesDirectory ,
79
+ '--properties' , /** propertiesToConsider */
80
+ ...this . propertiesToConsider ,
81
+ '--first-only' , /** compileAllFormats */
82
+ '--create-ivy-entry-points' , /** createNewEntryPointFormats */
83
+ '--async' ,
84
+ ] ,
85
+ {
86
+ stdio : [ 'inherit' , process . stderr , process . stderr ] ,
87
+ } ,
88
+ ) ;
89
+
90
+ if ( status !== 0 ) {
91
+ const errorMessage = error ?. message || '' ;
92
+ throw new Error ( errorMessage + `NGCC failed${ errorMessage ? ', see above' : '' } .` ) ;
93
+ }
94
+
95
+ timeEnd ( timeLabel ) ;
96
+ }
97
+
98
+ /** Process a module and it's depedencies. */
52
99
processModule (
53
100
moduleName : string ,
54
101
resolvedModule : ts . ResolvedModule | ts . ResolvedTypeReferenceDirective ,
@@ -61,18 +108,9 @@ export class NgccProcessor {
61
108
}
62
109
63
110
const packageJsonPath = this . tryResolvePackage ( moduleName , resolvedFileName ) ;
64
- if ( ! packageJsonPath ) {
65
- // add it to processed so the second time round we skip this.
66
- this . _processedModules . add ( resolvedFileName ) ;
67
-
68
- return ;
69
- }
70
-
71
111
// If the package.json is read only we should skip calling NGCC.
72
112
// With Bazel when running under sandbox the filesystem is read-only.
73
- try {
74
- accessSync ( packageJsonPath , constants . W_OK ) ;
75
- } catch {
113
+ if ( ! packageJsonPath || isReadOnlyFile ( packageJsonPath ) ) {
76
114
// add it to processed so the second time round we skip this.
77
115
this . _processedModules . add ( resolvedFileName ) ;
78
116
@@ -145,9 +183,9 @@ class NgccLogger implements Logger {
145
183
constructor (
146
184
private readonly compilationWarnings : ( Error | string ) [ ] ,
147
185
private readonly compilationErrors : ( Error | string ) [ ] ,
148
- ) { }
186
+ ) { }
149
187
150
- debug ( ..._args : string [ ] ) { }
188
+ debug ( ..._args : string [ ] ) { }
151
189
152
190
info ( ...args : string [ ] ) {
153
191
// Log to stderr because it's a progress-like info message.
@@ -162,3 +200,13 @@ class NgccLogger implements Logger {
162
200
this . compilationErrors . push ( new Error ( args . join ( ' ' ) ) ) ;
163
201
}
164
202
}
203
+
204
+ function isReadOnlyFile ( fileName : string ) : boolean {
205
+ try {
206
+ accessSync ( fileName , constants . W_OK ) ;
207
+
208
+ return false ;
209
+ } catch {
210
+ return true ;
211
+ }
212
+ }
0 commit comments