@angular-devkit/build-angular 17.0.0-rc.3 → 17.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/builders/application/execute-build.js +37 -28
- package/src/builders/dev-server/builder.d.ts +12 -1
- package/src/builders/dev-server/builder.js +13 -4
- package/src/builders/dev-server/vite-server.d.ts +9 -6
- package/src/builders/dev-server/vite-server.js +141 -63
- package/src/builders/karma/find-tests-plugin.js +17 -7
- package/src/builders/ssr-dev-server/index.d.ts +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +3 -1
- package/src/tools/esbuild/angular/compiler-plugin.js +103 -56
- package/src/tools/esbuild/application-code-bundle.js +1 -16
- package/src/tools/esbuild/bundler-context.d.ts +4 -1
- package/src/tools/esbuild/bundler-context.js +13 -8
- package/src/tools/esbuild/bundler-execution-result.d.ts +14 -14
- package/src/tools/esbuild/bundler-execution-result.js +4 -3
- package/src/tools/esbuild/commonjs-checker.js +9 -4
- package/src/tools/esbuild/global-scripts.d.ts +1 -1
- package/src/tools/esbuild/global-scripts.js +2 -1
- package/src/tools/esbuild/javascript-transformer.d.ts +1 -1
- package/src/tools/esbuild/javascript-transformer.js +20 -8
- package/src/utils/bundle-calculator.js +1 -1
- package/src/utils/environment-options.js +4 -1
- package/src/utils/load-esm.js +6 -1
- package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.d.ts +0 -4
- package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.js +77 -28
- package/src/utils/server-rendering/render-worker.js +3 -1
- package/src/utils/server-rendering/routes-extractor-worker.js +2 -2
|
@@ -89,18 +89,26 @@ async function findTests(include, exclude, workspaceRoot, projectSourceRoot) {
|
|
|
89
89
|
return [...new Set(files.flat())];
|
|
90
90
|
}
|
|
91
91
|
const normalizePath = (path) => path.replace(/\\/g, '/');
|
|
92
|
+
const removeLeadingSlash = (pattern) => {
|
|
93
|
+
if (pattern.charAt(0) === '/') {
|
|
94
|
+
return pattern.substring(1);
|
|
95
|
+
}
|
|
96
|
+
return pattern;
|
|
97
|
+
};
|
|
98
|
+
const removeRelativeRoot = (path, root) => {
|
|
99
|
+
if (path.startsWith(root)) {
|
|
100
|
+
return path.substring(root.length);
|
|
101
|
+
}
|
|
102
|
+
return path;
|
|
103
|
+
};
|
|
92
104
|
async function findMatchingTests(pattern, ignore, workspaceRoot, projectSourceRoot) {
|
|
93
105
|
// normalize pattern, glob lib only accepts forward slashes
|
|
94
106
|
let normalizedPattern = normalizePath(pattern);
|
|
95
|
-
|
|
96
|
-
normalizedPattern = normalizedPattern.substring(1);
|
|
97
|
-
}
|
|
107
|
+
normalizedPattern = removeLeadingSlash(normalizedPattern);
|
|
98
108
|
const relativeProjectRoot = normalizePath((0, path_1.relative)(workspaceRoot, projectSourceRoot) + '/');
|
|
99
109
|
// remove relativeProjectRoot to support relative paths from root
|
|
100
110
|
// such paths are easy to get when running scripts via IDEs
|
|
101
|
-
|
|
102
|
-
normalizedPattern = normalizedPattern.substring(relativeProjectRoot.length);
|
|
103
|
-
}
|
|
111
|
+
normalizedPattern = removeRelativeRoot(normalizedPattern, relativeProjectRoot);
|
|
104
112
|
// special logic when pattern does not look like a glob
|
|
105
113
|
if (!(0, fast_glob_1.isDynamicPattern)(normalizedPattern)) {
|
|
106
114
|
if (await isDirectory((0, path_1.join)(projectSourceRoot, normalizedPattern))) {
|
|
@@ -116,10 +124,12 @@ async function findMatchingTests(pattern, ignore, workspaceRoot, projectSourceRo
|
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
}
|
|
127
|
+
// normalize the patterns in the ignore list
|
|
128
|
+
const normalizedIgnorePatternList = ignore.map((pattern) => removeRelativeRoot(removeLeadingSlash(normalizePath(pattern)), relativeProjectRoot));
|
|
119
129
|
return (0, fast_glob_1.default)(normalizedPattern, {
|
|
120
130
|
cwd: projectSourceRoot,
|
|
121
131
|
absolute: true,
|
|
122
|
-
ignore: ['**/node_modules/**', ...
|
|
132
|
+
ignore: ['**/node_modules/**', ...normalizedIgnorePatternList],
|
|
123
133
|
});
|
|
124
134
|
}
|
|
125
135
|
async function isDirectory(path) {
|
|
@@ -9,7 +9,7 @@ import { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
|
|
|
9
9
|
import { json, logging } from '@angular-devkit/core';
|
|
10
10
|
import { Observable } from 'rxjs';
|
|
11
11
|
import { Schema } from './schema';
|
|
12
|
-
type SSRDevServerBuilderOptions = Schema & json.JsonObject;
|
|
12
|
+
export type SSRDevServerBuilderOptions = Schema & json.JsonObject;
|
|
13
13
|
export type SSRDevServerBuilderOutput = BuilderOutput & {
|
|
14
14
|
baseUrl?: string;
|
|
15
15
|
port?: string;
|
package/src/index.d.ts
CHANGED
|
@@ -14,4 +14,5 @@ export { execute as executeExtractI18nBuilder, ExtractI18nBuilderOptions, } from
|
|
|
14
14
|
export { execute as executeKarmaBuilder, KarmaBuilderOptions, KarmaConfigOptions, } from './builders/karma';
|
|
15
15
|
export { execute as executeProtractorBuilder, ProtractorBuilderOptions, } from './builders/protractor';
|
|
16
16
|
export { execute as executeServerBuilder, ServerBuilderOptions, ServerBuilderOutput, } from './builders/server';
|
|
17
|
+
export { execute as executeSSRDevServerBuilder, SSRDevServerBuilderOptions, SSRDevServerBuilderOutput, } from './builders/ssr-dev-server';
|
|
17
18
|
export { execute as executeNgPackagrBuilder, NgPackagrBuilderOptions } from './builders/ng-packagr';
|
package/src/index.js
CHANGED
|
@@ -21,7 +21,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
21
21
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.executeNgPackagrBuilder = exports.executeServerBuilder = exports.executeProtractorBuilder = exports.executeKarmaBuilder = exports.executeExtractI18nBuilder = exports.executeDevServerBuilder = exports.buildApplication = exports.executeBrowserBuilder = exports.Type = exports.OutputHashing = exports.CrossOrigin = void 0;
|
|
24
|
+
exports.executeNgPackagrBuilder = exports.executeSSRDevServerBuilder = exports.executeServerBuilder = exports.executeProtractorBuilder = exports.executeKarmaBuilder = exports.executeExtractI18nBuilder = exports.executeDevServerBuilder = exports.buildApplication = exports.executeBrowserBuilder = exports.Type = exports.OutputHashing = exports.CrossOrigin = void 0;
|
|
25
25
|
__exportStar(require("./transforms"), exports);
|
|
26
26
|
var schema_1 = require("./builders/browser/schema");
|
|
27
27
|
Object.defineProperty(exports, "CrossOrigin", { enumerable: true, get: function () { return schema_1.CrossOrigin; } });
|
|
@@ -41,5 +41,7 @@ var protractor_1 = require("./builders/protractor");
|
|
|
41
41
|
Object.defineProperty(exports, "executeProtractorBuilder", { enumerable: true, get: function () { return protractor_1.execute; } });
|
|
42
42
|
var server_1 = require("./builders/server");
|
|
43
43
|
Object.defineProperty(exports, "executeServerBuilder", { enumerable: true, get: function () { return server_1.execute; } });
|
|
44
|
+
var ssr_dev_server_1 = require("./builders/ssr-dev-server");
|
|
45
|
+
Object.defineProperty(exports, "executeSSRDevServerBuilder", { enumerable: true, get: function () { return ssr_dev_server_1.execute; } });
|
|
44
46
|
var ng_packagr_1 = require("./builders/ng-packagr");
|
|
45
47
|
Object.defineProperty(exports, "executeNgPackagrBuilder", { enumerable: true, get: function () { return ng_packagr_1.execute; } });
|
|
@@ -78,6 +78,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
78
78
|
const compilation = pluginOptions.noopTypeScriptCompilation
|
|
79
79
|
? new compilation_1.NoopCompilation()
|
|
80
80
|
: await (0, compilation_1.createAngularCompilation)(!!pluginOptions.jit);
|
|
81
|
+
// Compilation is initially assumed to have errors until emitted
|
|
82
|
+
let hasCompilationErrors = true;
|
|
81
83
|
// Determines if TypeScript should process JavaScript files based on tsconfig `allowJs` option
|
|
82
84
|
let shouldTsIgnoreJs = true;
|
|
83
85
|
// Track incremental component stylesheet builds
|
|
@@ -178,72 +180,59 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
178
180
|
};
|
|
179
181
|
// Initialize the Angular compilation for the current build.
|
|
180
182
|
// In watch mode, previous build state will be reused.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (compilerOptions.compilationMode === 'partial') {
|
|
203
|
-
setupWarnings?.push({
|
|
204
|
-
text: 'Angular partial compilation mode is not supported when building applications.',
|
|
205
|
-
location: null,
|
|
206
|
-
notes: [{ text: 'Full compilation mode will be used instead.' }],
|
|
207
|
-
});
|
|
208
|
-
compilerOptions.compilationMode = 'full';
|
|
209
|
-
}
|
|
210
|
-
// Enable incremental compilation by default if caching is enabled
|
|
211
|
-
if (pluginOptions.sourceFileCache?.persistentCachePath) {
|
|
212
|
-
compilerOptions.incremental ??= true;
|
|
213
|
-
// Set the build info file location to the configured cache directory
|
|
214
|
-
compilerOptions.tsBuildInfoFile = path.join(pluginOptions.sourceFileCache?.persistentCachePath, '.tsbuildinfo');
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
compilerOptions.incremental = false;
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
...compilerOptions,
|
|
221
|
-
noEmitOnError: false,
|
|
222
|
-
inlineSources: pluginOptions.sourcemap,
|
|
223
|
-
inlineSourceMap: pluginOptions.sourcemap,
|
|
224
|
-
mapRoot: undefined,
|
|
225
|
-
sourceRoot: undefined,
|
|
226
|
-
preserveSymlinks,
|
|
227
|
-
};
|
|
228
|
-
});
|
|
229
|
-
shouldTsIgnoreJs = !allowJs;
|
|
183
|
+
let referencedFiles;
|
|
184
|
+
try {
|
|
185
|
+
const initializationResult = await compilation.initialize(tsconfigPath, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks));
|
|
186
|
+
shouldTsIgnoreJs = !initializationResult.compilerOptions.allowJs;
|
|
187
|
+
referencedFiles = initializationResult.referencedFiles;
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
(result.errors ??= []).push({
|
|
191
|
+
text: 'Angular compilation initialization failed.',
|
|
192
|
+
location: null,
|
|
193
|
+
notes: [
|
|
194
|
+
{
|
|
195
|
+
text: error instanceof Error ? error.stack ?? error.message : `${error}`,
|
|
196
|
+
location: null,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
});
|
|
200
|
+
// Initialization failure prevents further compilation steps
|
|
201
|
+
hasCompilationErrors = true;
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
230
204
|
if (compilation instanceof compilation_1.NoopCompilation) {
|
|
231
205
|
await sharedTSCompilationState.waitUntilReady;
|
|
206
|
+
hasCompilationErrors = false;
|
|
232
207
|
return result;
|
|
233
208
|
}
|
|
234
209
|
const diagnostics = await compilation.diagnoseFiles();
|
|
235
|
-
if (diagnostics.errors) {
|
|
210
|
+
if (diagnostics.errors?.length) {
|
|
236
211
|
(result.errors ??= []).push(...diagnostics.errors);
|
|
237
212
|
}
|
|
238
|
-
if (diagnostics.warnings) {
|
|
213
|
+
if (diagnostics.warnings?.length) {
|
|
239
214
|
(result.warnings ??= []).push(...diagnostics.warnings);
|
|
240
215
|
}
|
|
241
216
|
// Update TypeScript file output cache for all affected files
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
217
|
+
try {
|
|
218
|
+
await (0, profiling_1.profileAsync)('NG_EMIT_TS', async () => {
|
|
219
|
+
for (const { filename, contents } of await compilation.emitAffectedFiles()) {
|
|
220
|
+
typeScriptFileCache.set((0, node_url_1.pathToFileURL)(filename).href, contents);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
(result.errors ??= []).push({
|
|
226
|
+
text: 'Angular compilation emit failed.',
|
|
227
|
+
location: null,
|
|
228
|
+
notes: [
|
|
229
|
+
{
|
|
230
|
+
text: error instanceof Error ? error.stack ?? error.message : `${error}`,
|
|
231
|
+
location: null,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
});
|
|
235
|
+
}
|
|
247
236
|
// Add errors from failed additional results.
|
|
248
237
|
// This must be done after emit to capture latest web worker results.
|
|
249
238
|
for (const { errors } of additionalResults.values()) {
|
|
@@ -258,6 +247,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
258
247
|
...referencedFileTracker.referencedFiles,
|
|
259
248
|
];
|
|
260
249
|
}
|
|
250
|
+
hasCompilationErrors = !!result.errors?.length;
|
|
261
251
|
// Reset the setup warnings so that they are only shown during the first build.
|
|
262
252
|
setupWarnings = undefined;
|
|
263
253
|
sharedTSCompilationState.markAsReady();
|
|
@@ -275,6 +265,11 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
275
265
|
// would need to be added to the key as well as a check for any change of content.
|
|
276
266
|
let contents = typeScriptFileCache.get((0, node_url_1.pathToFileURL)(request).href);
|
|
277
267
|
if (contents === undefined) {
|
|
268
|
+
// If the Angular compilation had errors the file may not have been emitted.
|
|
269
|
+
// To avoid additional errors about missing files, return empty contents.
|
|
270
|
+
if (hasCompilationErrors) {
|
|
271
|
+
return { contents: '', loader: 'js' };
|
|
272
|
+
}
|
|
278
273
|
// No TS result indicates the file is not part of the TypeScript program.
|
|
279
274
|
// If allowJs is enabled and the file is JS then defer to the next load hook.
|
|
280
275
|
if (!shouldTsIgnoreJs && /\.[cm]?js$/.test(request)) {
|
|
@@ -318,6 +313,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
318
313
|
(0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, styleOptions.inlineStyleLanguage);
|
|
319
314
|
}
|
|
320
315
|
build.onEnd((result) => {
|
|
316
|
+
// Ensure other compilations are unblocked if the main compilation throws during start
|
|
317
|
+
sharedTSCompilationState?.markAsReady();
|
|
321
318
|
for (const { outputFiles, metafile } of additionalResults.values()) {
|
|
322
319
|
// Add any additional output files to the main output files
|
|
323
320
|
if (outputFiles?.length) {
|
|
@@ -340,6 +337,56 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
340
337
|
};
|
|
341
338
|
}
|
|
342
339
|
exports.createCompilerPlugin = createCompilerPlugin;
|
|
340
|
+
function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks) {
|
|
341
|
+
return (compilerOptions) => {
|
|
342
|
+
// target of 9 is ES2022 (using the number avoids an expensive import of typescript just for an enum)
|
|
343
|
+
if (compilerOptions.target === undefined || compilerOptions.target < 9) {
|
|
344
|
+
// If 'useDefineForClassFields' is already defined in the users project leave the value as is.
|
|
345
|
+
// Otherwise fallback to false due to https://github.com/microsoft/TypeScript/issues/45995
|
|
346
|
+
// which breaks the deprecated `@Effects` NGRX decorator and potentially other existing code as well.
|
|
347
|
+
compilerOptions.target = 9;
|
|
348
|
+
compilerOptions.useDefineForClassFields ??= false;
|
|
349
|
+
// Only add the warning on the initial build
|
|
350
|
+
setupWarnings?.push({
|
|
351
|
+
text: 'TypeScript compiler options "target" and "useDefineForClassFields" are set to "ES2022" and ' +
|
|
352
|
+
'"false" respectively by the Angular CLI.',
|
|
353
|
+
location: { file: pluginOptions.tsconfig },
|
|
354
|
+
notes: [
|
|
355
|
+
{
|
|
356
|
+
text: 'To control ECMA version and features use the Browerslist configuration. ' +
|
|
357
|
+
'For more information, see https://angular.io/guide/build#configuring-browser-compatibility',
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (compilerOptions.compilationMode === 'partial') {
|
|
363
|
+
setupWarnings?.push({
|
|
364
|
+
text: 'Angular partial compilation mode is not supported when building applications.',
|
|
365
|
+
location: null,
|
|
366
|
+
notes: [{ text: 'Full compilation mode will be used instead.' }],
|
|
367
|
+
});
|
|
368
|
+
compilerOptions.compilationMode = 'full';
|
|
369
|
+
}
|
|
370
|
+
// Enable incremental compilation by default if caching is enabled
|
|
371
|
+
if (pluginOptions.sourceFileCache?.persistentCachePath) {
|
|
372
|
+
compilerOptions.incremental ??= true;
|
|
373
|
+
// Set the build info file location to the configured cache directory
|
|
374
|
+
compilerOptions.tsBuildInfoFile = path.join(pluginOptions.sourceFileCache?.persistentCachePath, '.tsbuildinfo');
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
compilerOptions.incremental = false;
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
...compilerOptions,
|
|
381
|
+
noEmitOnError: false,
|
|
382
|
+
inlineSources: pluginOptions.sourcemap,
|
|
383
|
+
inlineSourceMap: pluginOptions.sourcemap,
|
|
384
|
+
mapRoot: undefined,
|
|
385
|
+
sourceRoot: undefined,
|
|
386
|
+
preserveSymlinks,
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
}
|
|
343
390
|
function bundleWebWorker(build, pluginOptions, workerFile) {
|
|
344
391
|
try {
|
|
345
392
|
return build.esbuild.buildSync({
|
|
@@ -177,12 +177,9 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
177
177
|
exports.createServerCodeBundleOptions = createServerCodeBundleOptions;
|
|
178
178
|
function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
179
179
|
const polyfills = [];
|
|
180
|
-
const zoneFlagsNamespace = 'angular:zone-flags/placeholder';
|
|
181
180
|
const polyfillsFromConfig = new Set(options.polyfills);
|
|
182
|
-
let hasZoneJs = false;
|
|
183
181
|
if (polyfillsFromConfig.has('zone.js')) {
|
|
184
|
-
|
|
185
|
-
polyfills.push(zoneFlagsNamespace, 'zone.js/node');
|
|
182
|
+
polyfills.push('zone.js/node');
|
|
186
183
|
}
|
|
187
184
|
if (polyfillsFromConfig.has('@angular/localize') ||
|
|
188
185
|
polyfillsFromConfig.has('@angular/localize/init')) {
|
|
@@ -222,18 +219,6 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
222
219
|
},
|
|
223
220
|
};
|
|
224
221
|
buildOptions.plugins ??= [];
|
|
225
|
-
// Disable Zone.js uncaught promise rejections to provide cleaner stacktraces.
|
|
226
|
-
if (hasZoneJs) {
|
|
227
|
-
buildOptions.plugins.unshift((0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
228
|
-
namespace: zoneFlagsNamespace,
|
|
229
|
-
entryPointOnly: false,
|
|
230
|
-
loadContent: () => ({
|
|
231
|
-
contents: `globalThis.__zone_symbol__DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION = true;`,
|
|
232
|
-
loader: 'js',
|
|
233
|
-
resolveDir: workspaceRoot,
|
|
234
|
-
}),
|
|
235
|
-
}));
|
|
236
|
-
}
|
|
237
222
|
buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
|
|
238
223
|
return () => buildOptions;
|
|
239
224
|
}
|
|
@@ -16,7 +16,10 @@ export type BundleContextResult = {
|
|
|
16
16
|
metafile: Metafile;
|
|
17
17
|
outputFiles: BuildOutputFile[];
|
|
18
18
|
initialFiles: Map<string, InitialFileRecord>;
|
|
19
|
-
externalImports:
|
|
19
|
+
externalImports: {
|
|
20
|
+
server?: Set<string>;
|
|
21
|
+
browser?: Set<string>;
|
|
22
|
+
};
|
|
20
23
|
};
|
|
21
24
|
export interface InitialFileRecord {
|
|
22
25
|
entrypoint: boolean;
|
|
@@ -68,7 +68,8 @@ class BundlerContext {
|
|
|
68
68
|
const warnings = [];
|
|
69
69
|
const metafile = { inputs: {}, outputs: {} };
|
|
70
70
|
const initialFiles = new Map();
|
|
71
|
-
const
|
|
71
|
+
const externalImportsBrowser = new Set();
|
|
72
|
+
const externalImportsServer = new Set();
|
|
72
73
|
const outputFiles = [];
|
|
73
74
|
for (const result of individualResults) {
|
|
74
75
|
warnings.push(...result.warnings);
|
|
@@ -84,7 +85,8 @@ class BundlerContext {
|
|
|
84
85
|
}
|
|
85
86
|
result.initialFiles.forEach((value, key) => initialFiles.set(key, value));
|
|
86
87
|
outputFiles.push(...result.outputFiles);
|
|
87
|
-
result.externalImports.forEach((value) =>
|
|
88
|
+
result.externalImports.browser?.forEach((value) => externalImportsBrowser.add(value));
|
|
89
|
+
result.externalImports.server?.forEach((value) => externalImportsServer.add(value));
|
|
88
90
|
}
|
|
89
91
|
if (errors !== undefined) {
|
|
90
92
|
return { errors, warnings };
|
|
@@ -95,7 +97,10 @@ class BundlerContext {
|
|
|
95
97
|
metafile,
|
|
96
98
|
initialFiles,
|
|
97
99
|
outputFiles,
|
|
98
|
-
externalImports
|
|
100
|
+
externalImports: {
|
|
101
|
+
browser: externalImportsBrowser,
|
|
102
|
+
server: externalImportsServer,
|
|
103
|
+
},
|
|
99
104
|
};
|
|
100
105
|
}
|
|
101
106
|
/**
|
|
@@ -241,16 +246,14 @@ class BundlerContext {
|
|
|
241
246
|
externalImports.add(importData.path);
|
|
242
247
|
}
|
|
243
248
|
}
|
|
249
|
+
const platformIsServer = this.#esbuildOptions?.platform === 'node';
|
|
244
250
|
const outputFiles = result.outputFiles.map((file) => {
|
|
245
251
|
let fileType;
|
|
246
252
|
if ((0, node_path_1.dirname)(file.path) === 'media') {
|
|
247
253
|
fileType = BuildOutputFileType.Media;
|
|
248
254
|
}
|
|
249
255
|
else {
|
|
250
|
-
fileType =
|
|
251
|
-
this.#esbuildOptions?.platform === 'node'
|
|
252
|
-
? BuildOutputFileType.Server
|
|
253
|
-
: BuildOutputFileType.Browser;
|
|
256
|
+
fileType = platformIsServer ? BuildOutputFileType.Server : BuildOutputFileType.Browser;
|
|
254
257
|
}
|
|
255
258
|
return (0, utils_1.convertOutputFile)(file, fileType);
|
|
256
259
|
});
|
|
@@ -259,7 +262,9 @@ class BundlerContext {
|
|
|
259
262
|
...result,
|
|
260
263
|
outputFiles,
|
|
261
264
|
initialFiles,
|
|
262
|
-
externalImports
|
|
265
|
+
externalImports: {
|
|
266
|
+
[platformIsServer ? 'server' : 'browser']: externalImports,
|
|
267
|
+
},
|
|
263
268
|
errors: undefined,
|
|
264
269
|
};
|
|
265
270
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
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
|
-
import type { Message } from 'esbuild';
|
|
8
|
+
import type { Message, PartialMessage } from 'esbuild';
|
|
9
9
|
import type { ChangedFiles } from '../../tools/esbuild/watcher';
|
|
10
10
|
import type { SourceFileCache } from './angular/source-file-cache';
|
|
11
11
|
import type { BuildOutputFile, BuildOutputFileType, BundlerContext } from './bundler-context';
|
|
@@ -19,6 +19,11 @@ export interface RebuildState {
|
|
|
19
19
|
fileChanges: ChangedFiles;
|
|
20
20
|
previousOutputHashes: Map<string, string>;
|
|
21
21
|
}
|
|
22
|
+
export interface ExternalResultMetadata {
|
|
23
|
+
implicitBrowser: string[];
|
|
24
|
+
implicitServer: string[];
|
|
25
|
+
explicit: string[];
|
|
26
|
+
}
|
|
22
27
|
/**
|
|
23
28
|
* Represents the result of a single builder execute call.
|
|
24
29
|
*/
|
|
@@ -27,22 +32,20 @@ export declare class ExecutionResult {
|
|
|
27
32
|
private codeBundleCache?;
|
|
28
33
|
outputFiles: BuildOutputFile[];
|
|
29
34
|
assetFiles: BuildOutputAsset[];
|
|
30
|
-
errors: Message[];
|
|
31
|
-
externalMetadata?:
|
|
32
|
-
implicit: string[];
|
|
33
|
-
explicit?: string[];
|
|
34
|
-
};
|
|
35
|
+
errors: (Message | PartialMessage)[];
|
|
36
|
+
externalMetadata?: ExternalResultMetadata;
|
|
35
37
|
constructor(rebuildContexts: BundlerContext[], codeBundleCache?: SourceFileCache | undefined);
|
|
36
38
|
addOutputFile(path: string, content: string, type: BuildOutputFileType): void;
|
|
37
39
|
addAssets(assets: BuildOutputAsset[]): void;
|
|
38
|
-
addErrors(errors: Message[]): void;
|
|
40
|
+
addErrors(errors: (Message | PartialMessage)[]): void;
|
|
39
41
|
/**
|
|
40
42
|
* Add external JavaScript import metadata to the result. This is currently used
|
|
41
43
|
* by the development server to optimize the prebundling process.
|
|
42
|
-
* @param
|
|
44
|
+
* @param implicitBrowser External dependencies for the browser bundles due to the external packages option.
|
|
45
|
+
* @param implicitServer External dependencies for the server bundles due to the external packages option.
|
|
43
46
|
* @param explicit External dependencies due to explicit project configuration.
|
|
44
47
|
*/
|
|
45
|
-
setExternalMetadata(
|
|
48
|
+
setExternalMetadata(implicitBrowser: string[], implicitServer: string[], explicit: string[] | undefined): void;
|
|
46
49
|
get output(): {
|
|
47
50
|
success: boolean;
|
|
48
51
|
};
|
|
@@ -50,11 +53,8 @@ export declare class ExecutionResult {
|
|
|
50
53
|
success: boolean;
|
|
51
54
|
outputFiles: BuildOutputFile[];
|
|
52
55
|
assetFiles: BuildOutputAsset[];
|
|
53
|
-
errors: Message[];
|
|
54
|
-
externalMetadata:
|
|
55
|
-
implicit: string[];
|
|
56
|
-
explicit?: string[] | undefined;
|
|
57
|
-
} | undefined;
|
|
56
|
+
errors: (PartialMessage | Message)[];
|
|
57
|
+
externalMetadata: ExternalResultMetadata | undefined;
|
|
58
58
|
};
|
|
59
59
|
get watchFiles(): string[];
|
|
60
60
|
createRebuildState(fileChanges: ChangedFiles): RebuildState;
|
|
@@ -35,11 +35,12 @@ class ExecutionResult {
|
|
|
35
35
|
/**
|
|
36
36
|
* Add external JavaScript import metadata to the result. This is currently used
|
|
37
37
|
* by the development server to optimize the prebundling process.
|
|
38
|
-
* @param
|
|
38
|
+
* @param implicitBrowser External dependencies for the browser bundles due to the external packages option.
|
|
39
|
+
* @param implicitServer External dependencies for the server bundles due to the external packages option.
|
|
39
40
|
* @param explicit External dependencies due to explicit project configuration.
|
|
40
41
|
*/
|
|
41
|
-
setExternalMetadata(
|
|
42
|
-
this.externalMetadata = {
|
|
42
|
+
setExternalMetadata(implicitBrowser, implicitServer, explicit) {
|
|
43
|
+
this.externalMetadata = { implicitBrowser, implicitServer, explicit: explicit ?? [] };
|
|
43
44
|
}
|
|
44
45
|
get output() {
|
|
45
46
|
return {
|
|
@@ -38,6 +38,10 @@ function checkCommonJSModules(metafile, allowedCommonJsDependencies) {
|
|
|
38
38
|
// Used by '@angular/platform-server' and is in a seperate chunk that is unused when
|
|
39
39
|
// using `provideHttpClient(withFetch())`.
|
|
40
40
|
allowedRequests.add('xhr2');
|
|
41
|
+
// Packages used by @angular/ssr.
|
|
42
|
+
// While critters is ESM it has a number of direct and transtive CJS deps.
|
|
43
|
+
allowedRequests.add('express');
|
|
44
|
+
allowedRequests.add('critters');
|
|
41
45
|
// Find all entry points that contain code (JS/TS)
|
|
42
46
|
const files = [];
|
|
43
47
|
for (const { entryPoint } of Object.values(metafile.outputs)) {
|
|
@@ -62,6 +66,10 @@ function checkCommonJSModules(metafile, allowedCommonJsDependencies) {
|
|
|
62
66
|
continue;
|
|
63
67
|
}
|
|
64
68
|
seenFiles.add(imported.path);
|
|
69
|
+
// If the dependency is allowed ignore all other checks
|
|
70
|
+
if (allowedRequests.has(imported.original)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
65
73
|
// Only check actual code files
|
|
66
74
|
if (!isPathCode(imported.path)) {
|
|
67
75
|
continue;
|
|
@@ -117,10 +125,7 @@ function isPathCode(name) {
|
|
|
117
125
|
* @returns True, if specifier is potentially relative; false, otherwise.
|
|
118
126
|
*/
|
|
119
127
|
function isPotentialRelative(specifier) {
|
|
120
|
-
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
return false;
|
|
128
|
+
return specifier[0] === '.';
|
|
124
129
|
}
|
|
125
130
|
/**
|
|
126
131
|
* Creates an esbuild diagnostic message for a given non-ESM module request.
|
|
@@ -13,4 +13,4 @@ import { BundlerOptionsFactory } from './bundler-context';
|
|
|
13
13
|
* @param options The builder's user-provider normalized options.
|
|
14
14
|
* @returns An esbuild BuildOptions object.
|
|
15
15
|
*/
|
|
16
|
-
export declare function createGlobalScriptsBundleOptions(options: NormalizedApplicationBuildOptions, initial: boolean): BundlerOptionsFactory | undefined;
|
|
16
|
+
export declare function createGlobalScriptsBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], initial: boolean): BundlerOptionsFactory | undefined;
|
|
@@ -48,7 +48,7 @@ const virtual_module_plugin_1 = require("./virtual-module-plugin");
|
|
|
48
48
|
* @param options The builder's user-provider normalized options.
|
|
49
49
|
* @returns An esbuild BuildOptions object.
|
|
50
50
|
*/
|
|
51
|
-
function createGlobalScriptsBundleOptions(options, initial) {
|
|
51
|
+
function createGlobalScriptsBundleOptions(options, target, initial) {
|
|
52
52
|
const { globalScripts, optimizationOptions, outputNames, preserveSymlinks, sourcemapOptions, workspaceRoot, } = options;
|
|
53
53
|
const namespace = 'angular:script/global';
|
|
54
54
|
const entryPoints = {};
|
|
@@ -81,6 +81,7 @@ function createGlobalScriptsBundleOptions(options, initial) {
|
|
|
81
81
|
sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
82
82
|
write: false,
|
|
83
83
|
platform: 'neutral',
|
|
84
|
+
target,
|
|
84
85
|
preserveSymlinks,
|
|
85
86
|
plugins: [
|
|
86
87
|
(0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
|
|
@@ -24,7 +24,7 @@ export interface JavaScriptTransformerOptions {
|
|
|
24
24
|
export declare class JavaScriptTransformer {
|
|
25
25
|
#private;
|
|
26
26
|
readonly maxThreads: number;
|
|
27
|
-
constructor(options: JavaScriptTransformerOptions, maxThreads: number);
|
|
27
|
+
constructor(options: JavaScriptTransformerOptions, maxThreads: number, reuseResults?: boolean);
|
|
28
28
|
/**
|
|
29
29
|
* Performs JavaScript transformations on a file from the filesystem.
|
|
30
30
|
* If no transformations are required, the data for the original file will be returned.
|
|
@@ -23,7 +23,8 @@ class JavaScriptTransformer {
|
|
|
23
23
|
maxThreads;
|
|
24
24
|
#workerPool;
|
|
25
25
|
#commonOptions;
|
|
26
|
-
|
|
26
|
+
#pendingfileResults;
|
|
27
|
+
constructor(options, maxThreads, reuseResults) {
|
|
27
28
|
this.maxThreads = maxThreads;
|
|
28
29
|
// Extract options to ensure only the named options are serialized and sent to the worker
|
|
29
30
|
const { sourcemap, thirdPartySourcemaps = false, advancedOptimizations = false, jit = false, } = options;
|
|
@@ -33,6 +34,10 @@ class JavaScriptTransformer {
|
|
|
33
34
|
advancedOptimizations,
|
|
34
35
|
jit,
|
|
35
36
|
};
|
|
37
|
+
// Currently only tracks pending file transform results
|
|
38
|
+
if (reuseResults) {
|
|
39
|
+
this.#pendingfileResults = new Map();
|
|
40
|
+
}
|
|
36
41
|
}
|
|
37
42
|
#ensureWorkerPool() {
|
|
38
43
|
this.#workerPool ??= new piscina_1.default({
|
|
@@ -52,13 +57,19 @@ class JavaScriptTransformer {
|
|
|
52
57
|
* @returns A promise that resolves to a UTF-8 encoded Uint8Array containing the result.
|
|
53
58
|
*/
|
|
54
59
|
transformFile(filename, skipLinker) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const pendingKey = `${!!skipLinker}--${filename}`;
|
|
61
|
+
let pending = this.#pendingfileResults?.get(pendingKey);
|
|
62
|
+
if (pending === undefined) {
|
|
63
|
+
// Always send the request to a worker. Files are almost always from node modules which means
|
|
64
|
+
// they may need linking. The data is also not yet available to perform most transformation checks.
|
|
65
|
+
pending = this.#ensureWorkerPool().run({
|
|
66
|
+
filename,
|
|
67
|
+
skipLinker,
|
|
68
|
+
...this.#commonOptions,
|
|
69
|
+
});
|
|
70
|
+
this.#pendingfileResults?.set(pendingKey, pending);
|
|
71
|
+
}
|
|
72
|
+
return pending;
|
|
62
73
|
}
|
|
63
74
|
/**
|
|
64
75
|
* Performs JavaScript transformations on the provided data of a file. The file does not need
|
|
@@ -88,6 +99,7 @@ class JavaScriptTransformer {
|
|
|
88
99
|
* @returns A void promise that resolves when closing is complete.
|
|
89
100
|
*/
|
|
90
101
|
async close() {
|
|
102
|
+
this.#pendingfileResults?.clear();
|
|
91
103
|
if (this.#workerPool) {
|
|
92
104
|
// Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
|
|
93
105
|
this.#workerPool.options.minThreads = 0;
|
|
@@ -228,7 +228,7 @@ class AnyComponentStyleCalculator extends Calculator {
|
|
|
228
228
|
* Calculate the bytes given a string value.
|
|
229
229
|
*/
|
|
230
230
|
function calculateBytes(input, baseline, factor = 1) {
|
|
231
|
-
const matches = input.match(
|
|
231
|
+
const matches = input.trim().match(/^(\d+(?:\.\d+)?)[ \t]*(%|[kmg]?b)?$/i);
|
|
232
232
|
if (!matches) {
|
|
233
233
|
return NaN;
|
|
234
234
|
}
|
|
@@ -68,8 +68,11 @@ exports.allowMinify = debugOptimize.minify;
|
|
|
68
68
|
*/
|
|
69
69
|
const maxWorkersVariable = process.env['NG_BUILD_MAX_WORKERS'];
|
|
70
70
|
exports.maxWorkers = isPresent(maxWorkersVariable) ? +maxWorkersVariable : 4;
|
|
71
|
+
// Default to enabled unless inside a Web Container which currently fails when transferring MessagePort objects
|
|
71
72
|
const parallelTsVariable = process.env['NG_BUILD_PARALLEL_TS'];
|
|
72
|
-
exports.useParallelTs =
|
|
73
|
+
exports.useParallelTs = isPresent(parallelTsVariable)
|
|
74
|
+
? !isDisabled(parallelTsVariable)
|
|
75
|
+
: !process.versions.webcontainer;
|
|
73
76
|
const legacySassVariable = process.env['NG_BUILD_LEGACY_SASS'];
|
|
74
77
|
exports.useLegacySass = (() => {
|
|
75
78
|
if (!isPresent(legacySassVariable)) {
|