forked from angular/angular
/
ngcc_options.ts
281 lines (251 loc) · 10.9 KB
/
ngcc_options.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as os from 'os';
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '../../src/ngtsc/file_system';
import {ConsoleLogger, Logger, LogLevel} from '../../src/ngtsc/logging';
import {ParsedConfiguration, readConfiguration} from '../../src/perform_compile';
import {SUPPORTED_FORMAT_PROPERTIES} from './packages/entry_point';
import {getPathMappingsFromTsConfig, PathMappings} from './path_mappings';
import {FileWriter} from './writing/file_writer';
import {InPlaceFileWriter} from './writing/in_place_file_writer';
import {NewEntryPointFileWriter} from './writing/new_entry_point_file_writer';
import {PackageJsonUpdater} from './writing/package_json_updater';
/**
* The options to configure the ngcc compiler for synchronous execution.
*/
export interface SyncNgccOptions {
/** The absolute path to the `node_modules` folder that contains the packages to process. */
basePath: string;
/**
* The path to the primary package to be processed. If not absolute then it must be relative to
* `basePath`.
*
* All its dependencies will need to be processed too.
*
* If this property is provided then `errorOnFailedEntryPoint` is forced to true.
*/
targetEntryPointPath?: string;
/**
* Which entry-point properties in the package.json to consider when processing an entry-point.
* Each property should hold a path to the particular bundle format for the entry-point.
* Defaults to all the properties in the package.json.
*/
propertiesToConsider?: string[];
/**
* Whether to process all formats specified by (`propertiesToConsider`) or to stop processing
* this entry-point at the first matching format. Defaults to `true`.
*/
compileAllFormats?: boolean;
/**
* Whether to create new entry-points bundles rather than overwriting the original files.
*/
createNewEntryPointFormats?: boolean;
/**
* Provide a logger that will be called with log messages.
*/
logger?: Logger;
/**
* Paths mapping configuration (`paths` and `baseUrl`), as found in `ts.CompilerOptions`.
* These are used to resolve paths to locally built Angular libraries.
*
* Note that `pathMappings` specified here take precedence over any `pathMappings` loaded from a
* TS config file.
*/
pathMappings?: PathMappings;
/**
* Provide a file-system service that will be used by ngcc for all file interactions.
*/
fileSystem?: FileSystem;
/**
* Whether the compilation should run and return asynchronously. Allowing asynchronous execution
* may speed up the compilation by utilizing multiple CPU cores (if available).
*
* Default: `false` (i.e. run synchronously)
*/
async?: false;
/**
* Set to true in order to terminate immediately with an error code if an entry-point fails to be
* processed.
*
* If `targetEntryPointPath` is provided then this property is always true and cannot be
* changed. Otherwise the default is false.
*
* When set to false, ngcc will continue to process entry-points after a failure. In which case it
* will log an error and resume processing other entry-points.
*/
errorOnFailedEntryPoint?: boolean;
/**
* Render `$localize` messages with legacy format ids.
*
* The default value is `true`. Only set this to `false` if you do not want legacy message ids to
* be rendered. For example, if you are not using legacy message ids in your translation files
* AND are not doing compile-time inlining of translations, in which case the extra message ids
* would add unwanted size to the final source bundle.
*
* It is safe to leave this set to true if you are doing compile-time inlining because the extra
* legacy message ids will all be stripped during translation.
*/
enableI18nLegacyMessageIdFormat?: boolean;
/**
* Whether to invalidate any entry-point manifest file that is on disk. Instead, walk the
* directory tree looking for entry-points, and then write a new entry-point manifest, if
* possible.
*
* Default: `false` (i.e. the manifest will be used if available)
*/
invalidateEntryPointManifest?: boolean;
/**
* An absolute path to a TS config file (e.g. `tsconfig.json`) or a directory containing one, that
* will be used to configure module resolution with things like path mappings, if not specified
* explicitly via the `pathMappings` property to `mainNgcc`.
*
* If `undefined`, ngcc will attempt to load a `tsconfig.json` file from the directory above the
* `basePath`.
*
* If `null`, ngcc will not attempt to load any TS config file at all.
*/
tsConfigPath?: string|null;
/**
* Use the program defined in the loaded tsconfig.json (if available - see
* `tsConfigPath` option) to identify the entry-points that should be processed.
* If this is set to `true` then only the entry-points reachable from the given
* program (and their dependencies) will be processed.
*/
findEntryPointsFromTsConfigProgram?: boolean;
}
/**
* The options to configure the ngcc compiler for asynchronous execution.
*/
export type AsyncNgccOptions = Omit<SyncNgccOptions, 'async'>&{async: true};
/**
* The options to configure the ngcc compiler.
*/
export type NgccOptions = AsyncNgccOptions|SyncNgccOptions;
export type OptionalNgccOptionKeys =
'targetEntryPointPath'|'tsConfigPath'|'pathMappings'|'findEntryPointsFromTsConfigProgram';
export type RequiredNgccOptions = Required<Omit<NgccOptions, OptionalNgccOptionKeys>>;
export type OptionalNgccOptions = Pick<NgccOptions, OptionalNgccOptionKeys>;
export type SharedSetup = {
fileSystem: FileSystem; absBasePath: AbsoluteFsPath; projectPath: AbsoluteFsPath;
tsConfig: ParsedConfiguration | null;
getFileWriter(pkgJsonUpdater: PackageJsonUpdater): FileWriter;
};
/**
* Instantiate common utilities that are always used and fix up options with defaults, as necessary.
*
* NOTE: Avoid eagerly instantiating anything that might not be used when running sync/async.
*/
export function getSharedSetup(options: NgccOptions): SharedSetup&RequiredNgccOptions&
OptionalNgccOptions {
const fileSystem = getFileSystem();
const absBasePath = absoluteFrom(options.basePath);
const projectPath = fileSystem.dirname(absBasePath);
const tsConfig =
options.tsConfigPath !== null ? getTsConfig(options.tsConfigPath || projectPath) : null;
let {
basePath,
targetEntryPointPath,
propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
compileAllFormats = true,
createNewEntryPointFormats = false,
logger = new ConsoleLogger(LogLevel.info),
pathMappings = getPathMappingsFromTsConfig(tsConfig, projectPath),
async = false,
errorOnFailedEntryPoint = false,
enableI18nLegacyMessageIdFormat = true,
invalidateEntryPointManifest = false,
tsConfigPath,
} = options;
if (!!targetEntryPointPath) {
// targetEntryPointPath forces us to error if an entry-point fails.
errorOnFailedEntryPoint = true;
}
checkForSolutionStyleTsConfig(fileSystem, logger, projectPath, options.tsConfigPath, tsConfig);
return {
basePath,
targetEntryPointPath,
propertiesToConsider,
compileAllFormats,
createNewEntryPointFormats,
logger,
pathMappings,
async,
errorOnFailedEntryPoint,
enableI18nLegacyMessageIdFormat,
invalidateEntryPointManifest,
tsConfigPath,
fileSystem,
absBasePath,
projectPath,
tsConfig,
getFileWriter: (pkgJsonUpdater: PackageJsonUpdater) => createNewEntryPointFormats ?
new NewEntryPointFileWriter(fileSystem, logger, errorOnFailedEntryPoint, pkgJsonUpdater) :
new InPlaceFileWriter(fileSystem, logger, errorOnFailedEntryPoint),
};
}
let tsConfigCache: ParsedConfiguration|null = null;
let tsConfigPathCache: string|null = null;
/**
* Get the parsed configuration object for the given `tsConfigPath`.
*
* This function will cache the previous parsed configuration object to avoid unnecessary processing
* of the tsconfig.json in the case that it is requested repeatedly.
*
* This makes the assumption, which is true as of writing, that the contents of tsconfig.json and
* its dependencies will not change during the life of the process running ngcc.
*/
function getTsConfig(tsConfigPath: string): ParsedConfiguration|null {
if (tsConfigPath !== tsConfigPathCache) {
tsConfigPathCache = tsConfigPath;
tsConfigCache = readConfiguration(tsConfigPath);
}
return tsConfigCache;
}
export function clearTsConfigCache() {
tsConfigPathCache = null;
tsConfigCache = null;
}
function checkForSolutionStyleTsConfig(
fileSystem: FileSystem, logger: Logger, projectPath: AbsoluteFsPath,
tsConfigPath: string|null|undefined, tsConfig: ParsedConfiguration|null): void {
if (tsConfigPath !== null && !tsConfigPath && tsConfig !== null &&
tsConfig.rootNames.length === 0 && tsConfig.projectReferences !== undefined &&
tsConfig.projectReferences.length > 0) {
logger.warn(
`The inferred tsconfig file "${tsConfig.project}" appears to be "solution-style" ` +
`since it contains no root files but does contain project references.\n` +
`This is probably not wanted, since ngcc is unable to infer settings like "paths" mappings from such a file.\n` +
`Perhaps you should have explicitly specified one of the referenced projects using the --tsconfig option. For example:\n\n` +
tsConfig.projectReferences.map(ref => ` ngcc ... --tsconfig "${ref.originalPath}"\n`)
.join('') +
`\nFind out more about solution-style tsconfig at https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig.\n` +
`If you did intend to use this file, then you can hide this warning by providing it explicitly:\n\n` +
` ngcc ... --tsconfig "${fileSystem.relative(projectPath, tsConfig.project)}"`);
}
}
/**
* Determines the maximum number of workers to use for parallel execution. This can be set using the
* NGCC_MAX_WORKERS environment variable, or is computed based on the number of available CPUs. One
* CPU core is always reserved for the master process, so we take the number of CPUs minus one, with
* a maximum of 4 workers. We don't scale the number of workers beyond 4 by default, as it takes
* considerably more memory and CPU cycles while not offering a substantial improvement in time.
*/
export function getMaxNumberOfWorkers(): number {
const maxWorkers = process.env.NGCC_MAX_WORKERS;
if (maxWorkers === undefined) {
// Use up to 4 CPU cores for workers, always reserving one for master.
return Math.max(1, Math.min(4, os.cpus().length - 1));
}
const numericMaxWorkers = +maxWorkers.trim();
if (!Number.isInteger(numericMaxWorkers)) {
throw new Error('NGCC_MAX_WORKERS should be an integer.');
} else if (numericMaxWorkers < 1) {
throw new Error('NGCC_MAX_WORKERS should be at least 1.');
}
return numericMaxWorkers;
}