@angular/build 19.0.0-next.9 → 19.0.0-rc.1
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 +21 -19
- package/src/builders/application/build-action.js +22 -10
- package/src/builders/application/chunk-optimizer.js +1 -4
- package/src/builders/application/execute-build.js +59 -24
- package/src/builders/application/execute-post-bundle.js +28 -5
- package/src/builders/application/index.d.ts +0 -16
- package/src/builders/application/index.js +15 -10
- package/src/builders/application/options.d.ts +14 -2
- package/src/builders/application/options.js +25 -10
- package/src/builders/application/results.d.ts +5 -3
- package/src/builders/application/schema.d.ts +86 -0
- package/src/builders/application/schema.js +19 -1
- package/src/builders/application/schema.json +73 -4
- package/src/builders/application/setup-bundling.d.ts +6 -1
- package/src/builders/application/setup-bundling.js +47 -13
- package/src/builders/dev-server/options.d.ts +2 -2
- package/src/builders/dev-server/options.js +2 -2
- package/src/builders/dev-server/schema.d.ts +2 -1
- package/src/builders/dev-server/schema.json +1 -2
- package/src/builders/dev-server/vite-server.d.ts +3 -2
- package/src/builders/dev-server/vite-server.js +123 -61
- package/src/index.d.ts +1 -0
- package/src/tools/angular/angular-host.d.ts +1 -1
- package/src/tools/angular/angular-host.js +14 -6
- package/src/tools/angular/compilation/angular-compilation.d.ts +1 -0
- package/src/tools/angular/compilation/aot-compilation.d.ts +1 -0
- package/src/tools/angular/compilation/aot-compilation.js +39 -0
- package/src/tools/angular/compilation/parallel-compilation.js +2 -2
- package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
- package/src/tools/angular/compilation/parallel-worker.js +5 -2
- package/src/tools/esbuild/angular/compiler-plugin.d.ts +3 -4
- package/src/tools/esbuild/angular/compiler-plugin.js +58 -33
- package/src/tools/esbuild/angular/component-stylesheets.d.ts +18 -18
- package/src/tools/esbuild/angular/component-stylesheets.js +66 -38
- package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +1 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.js +11 -3
- package/src/tools/esbuild/angular/source-file-cache.d.ts +1 -1
- package/src/tools/esbuild/angular/source-file-cache.js +6 -2
- package/src/tools/esbuild/application-code-bundle.d.ts +7 -5
- package/src/tools/esbuild/application-code-bundle.js +280 -249
- package/src/tools/esbuild/bundler-context.d.ts +2 -1
- package/src/tools/esbuild/bundler-context.js +10 -12
- package/src/tools/esbuild/bundler-execution-result.d.ts +14 -3
- package/src/tools/esbuild/bundler-execution-result.js +15 -8
- package/src/tools/esbuild/commonjs-checker.js +2 -2
- package/src/tools/esbuild/compiler-plugin-options.d.ts +2 -4
- package/src/tools/esbuild/compiler-plugin-options.js +15 -37
- package/src/tools/esbuild/global-scripts.js +1 -1
- package/src/tools/esbuild/global-styles.js +4 -1
- package/src/tools/esbuild/index-html-generator.js +8 -0
- package/src/tools/esbuild/javascript-transformer.js +3 -0
- package/src/tools/esbuild/server-bundle-metadata-plugin.d.ts +22 -0
- package/src/tools/esbuild/server-bundle-metadata-plugin.js +36 -0
- package/src/tools/esbuild/stylesheets/bundle-options.d.ts +2 -0
- package/src/tools/esbuild/stylesheets/bundle-options.js +2 -1
- package/src/tools/esbuild/stylesheets/sass-language.js +4 -0
- package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.d.ts +9 -0
- package/src/tools/esbuild/utils.js +13 -31
- package/src/tools/sass/worker.js +19 -0
- package/src/tools/vite/middlewares/assets-middleware.d.ts +6 -1
- package/src/tools/vite/middlewares/assets-middleware.js +42 -22
- package/src/tools/vite/middlewares/component-middleware.d.ts +9 -0
- package/src/tools/vite/middlewares/component-middleware.js +33 -0
- package/src/tools/vite/middlewares/index.d.ts +2 -1
- package/src/tools/vite/middlewares/index.js +3 -1
- package/src/tools/vite/middlewares/ssr-middleware.js +11 -8
- package/src/tools/vite/plugins/angular-memory-plugin.d.ts +1 -0
- package/src/tools/vite/plugins/angular-memory-plugin.js +5 -13
- package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +3 -1
- package/src/tools/vite/plugins/setup-middlewares-plugin.js +12 -3
- package/src/tools/vite/utils.d.ts +1 -0
- package/src/typings.d.ts +1 -1
- package/src/utils/environment-options.d.ts +1 -0
- package/src/utils/environment-options.js +4 -2
- package/src/utils/index-file/auto-csp.d.ts +23 -0
- package/src/utils/index-file/auto-csp.js +283 -0
- package/src/utils/index-file/html-rewriting-stream.d.ts +5 -1
- package/src/utils/index-file/index-html-generator.d.ts +4 -0
- package/src/utils/index-file/index-html-generator.js +11 -0
- package/src/utils/index-file/inline-critical-css.js +17 -18
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/server-rendering/esm-in-memory-loader/utils.d.ts +8 -0
- package/src/utils/server-rendering/esm-in-memory-loader/utils.js +13 -0
- package/src/utils/server-rendering/launch-server.js +5 -5
- package/src/utils/server-rendering/load-esm-from-memory.d.ts +1 -1
- package/src/utils/server-rendering/manifest.d.ts +9 -8
- package/src/utils/server-rendering/manifest.js +17 -23
- package/src/utils/server-rendering/prerender.js +30 -19
- package/src/utils/server-rendering/render-worker.js +4 -2
- package/src/utils/supported-browsers.js +1 -0
|
@@ -43,11 +43,10 @@ const javascript_transformer_1 = require("../javascript-transformer");
|
|
|
43
43
|
const load_result_cache_1 = require("../load-result-cache");
|
|
44
44
|
const profiling_1 = require("../profiling");
|
|
45
45
|
const compilation_state_1 = require("./compilation-state");
|
|
46
|
-
const component_stylesheets_1 = require("./component-stylesheets");
|
|
47
46
|
const file_reference_tracker_1 = require("./file-reference-tracker");
|
|
48
47
|
const jit_plugin_callbacks_1 = require("./jit-plugin-callbacks");
|
|
49
48
|
// eslint-disable-next-line max-lines-per-function
|
|
50
|
-
function createCompilerPlugin(pluginOptions,
|
|
49
|
+
function createCompilerPlugin(pluginOptions, stylesheetBundler) {
|
|
51
50
|
return {
|
|
52
51
|
name: 'angular-compiler',
|
|
53
52
|
// eslint-disable-next-line max-lines-per-function
|
|
@@ -101,8 +100,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
101
100
|
let shouldTsIgnoreJs = true;
|
|
102
101
|
// Determines if transpilation should be handle by TypeScript or esbuild
|
|
103
102
|
let useTypeScriptTranspilation = true;
|
|
104
|
-
// Track incremental component stylesheet builds
|
|
105
|
-
const stylesheetBundler = new component_stylesheets_1.ComponentStylesheetBundler(styleOptions, pluginOptions.incremental);
|
|
106
103
|
let sharedTSCompilationState;
|
|
107
104
|
// To fully invalidate files, track resource referenced files and their referencing source
|
|
108
105
|
const referencedFileTracker = new file_reference_tracker_1.FileReferenceTracker();
|
|
@@ -121,14 +118,17 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
121
118
|
// Angular compiler which does not have direct knowledge of transitive resource
|
|
122
119
|
// dependencies or web worker processing.
|
|
123
120
|
let modifiedFiles;
|
|
124
|
-
let invalidatedStylesheetEntries;
|
|
125
121
|
if (pluginOptions.sourceFileCache?.modifiedFiles.size &&
|
|
126
122
|
referencedFileTracker &&
|
|
127
123
|
!pluginOptions.noopTypeScriptCompilation) {
|
|
128
124
|
// TODO: Differentiate between changed input files and stale output files
|
|
129
125
|
modifiedFiles = referencedFileTracker.update(pluginOptions.sourceFileCache.modifiedFiles);
|
|
130
126
|
pluginOptions.sourceFileCache.invalidate(modifiedFiles);
|
|
131
|
-
|
|
127
|
+
// External runtime styles are invalidated and rebuilt at the beginning of a rebuild to avoid
|
|
128
|
+
// the need to execute the application bundler for component style only changes.
|
|
129
|
+
if (!pluginOptions.externalRuntimeStyles) {
|
|
130
|
+
stylesheetBundler.invalidate(modifiedFiles);
|
|
131
|
+
}
|
|
132
132
|
}
|
|
133
133
|
if (!pluginOptions.noopTypeScriptCompilation &&
|
|
134
134
|
compilation.update &&
|
|
@@ -140,7 +140,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
140
140
|
fileReplacements: pluginOptions.fileReplacements,
|
|
141
141
|
modifiedFiles,
|
|
142
142
|
sourceFileCache: pluginOptions.sourceFileCache,
|
|
143
|
-
async transformStylesheet(data, containingFile, stylesheetFile, order) {
|
|
143
|
+
async transformStylesheet(data, containingFile, stylesheetFile, order, className) {
|
|
144
144
|
let stylesheetResult;
|
|
145
145
|
// Stylesheet file only exists for external stylesheets
|
|
146
146
|
if (stylesheetFile) {
|
|
@@ -148,8 +148,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
148
148
|
}
|
|
149
149
|
else {
|
|
150
150
|
stylesheetResult = await stylesheetBundler.bundleInline(data, containingFile,
|
|
151
|
-
// Inline stylesheets from a template style element are always CSS
|
|
152
|
-
containingFile.endsWith('.html') ? 'css' :
|
|
151
|
+
// Inline stylesheets from a template style element are always CSS; Otherwise, use default.
|
|
152
|
+
containingFile.endsWith('.html') ? 'css' : undefined,
|
|
153
153
|
// When external runtime styles are enabled, an identifier for the style that does not change
|
|
154
154
|
// based on the content is required to avoid emitted JS code changes. Any JS code changes will
|
|
155
155
|
// invalid the output and force a full page reload for HMR cases. The containing file and order
|
|
@@ -158,14 +158,16 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
158
158
|
? (0, node_crypto_1.createHash)('sha-256')
|
|
159
159
|
.update(containingFile)
|
|
160
160
|
.update((order ?? 0).toString())
|
|
161
|
+
.update(className ?? '')
|
|
161
162
|
.digest('hex')
|
|
162
163
|
: undefined);
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
-
if (errors) {
|
|
166
|
-
(result.errors ??= []).push(...errors);
|
|
165
|
+
(result.warnings ??= []).push(...stylesheetResult.warnings);
|
|
166
|
+
if (stylesheetResult.errors) {
|
|
167
|
+
(result.errors ??= []).push(...stylesheetResult.errors);
|
|
168
|
+
return '';
|
|
167
169
|
}
|
|
168
|
-
|
|
170
|
+
const { contents, outputFiles, metafile, referencedFiles } = stylesheetResult;
|
|
169
171
|
additionalResults.set(stylesheetFile ?? containingFile, {
|
|
170
172
|
outputFiles,
|
|
171
173
|
metafile,
|
|
@@ -215,7 +217,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
215
217
|
let referencedFiles;
|
|
216
218
|
let externalStylesheets;
|
|
217
219
|
try {
|
|
218
|
-
const initializationResult = await compilation.initialize(pluginOptions.tsconfig, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks));
|
|
220
|
+
const initializationResult = await compilation.initialize(pluginOptions.tsconfig, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, build.initialOptions.conditions));
|
|
219
221
|
shouldTsIgnoreJs = !initializationResult.compilerOptions.allowJs;
|
|
220
222
|
// Isolated modules option ensures safe non-TypeScript transpilation.
|
|
221
223
|
// Typescript printing support for sourcemaps is not yet integrated.
|
|
@@ -225,6 +227,10 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
225
227
|
!!initializationResult.compilerOptions.inlineSourceMap;
|
|
226
228
|
referencedFiles = initializationResult.referencedFiles;
|
|
227
229
|
externalStylesheets = initializationResult.externalStylesheets;
|
|
230
|
+
if (initializationResult.templateUpdates) {
|
|
231
|
+
// Propagate any template updates
|
|
232
|
+
initializationResult.templateUpdates.forEach((value, key) => pluginOptions.templateUpdates?.set(key, value));
|
|
233
|
+
}
|
|
228
234
|
}
|
|
229
235
|
catch (error) {
|
|
230
236
|
(result.errors ??= []).push({
|
|
@@ -250,13 +256,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
250
256
|
for (const [stylesheetFile, externalId] of externalStylesheets) {
|
|
251
257
|
await bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults);
|
|
252
258
|
}
|
|
253
|
-
// Process any updated stylesheets
|
|
254
|
-
if (invalidatedStylesheetEntries) {
|
|
255
|
-
for (const stylesheetFile of invalidatedStylesheetEntries) {
|
|
256
|
-
// externalId is already linked in the bundler context so only enabling is required here
|
|
257
|
-
await bundleExternalStylesheet(stylesheetBundler, stylesheetFile, true, result, additionalResults);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
259
|
}
|
|
261
260
|
// Update TypeScript file output cache for all affected files
|
|
262
261
|
try {
|
|
@@ -344,9 +343,22 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
344
343
|
// Store as the returned Uint8Array to allow caching the fully transformed code
|
|
345
344
|
typeScriptFileCache.set(request, contents);
|
|
346
345
|
}
|
|
346
|
+
let loader;
|
|
347
|
+
if (useTypeScriptTranspilation || isJS) {
|
|
348
|
+
// TypeScript has transpiled to JS or is already JS
|
|
349
|
+
loader = 'js';
|
|
350
|
+
}
|
|
351
|
+
else if (request.at(-1) === 'x') {
|
|
352
|
+
// TSX and TS have different syntax rules. Only set if input is a TSX file.
|
|
353
|
+
loader = 'tsx';
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
// Otherwise, directly bundle TS
|
|
357
|
+
loader = 'ts';
|
|
358
|
+
}
|
|
347
359
|
return {
|
|
348
360
|
contents,
|
|
349
|
-
loader
|
|
361
|
+
loader,
|
|
350
362
|
};
|
|
351
363
|
});
|
|
352
364
|
build.onLoad({ filter: /\.[cm]?js$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
|
|
@@ -361,7 +373,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
361
373
|
}));
|
|
362
374
|
// Setup bundling of component templates and stylesheets when in JIT mode
|
|
363
375
|
if (pluginOptions.jit) {
|
|
364
|
-
(0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults,
|
|
376
|
+
(0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, pluginOptions.loadResultCache);
|
|
365
377
|
}
|
|
366
378
|
build.onEnd((result) => {
|
|
367
379
|
// Ensure other compilations are unblocked if the main compilation throws during start
|
|
@@ -384,7 +396,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
384
396
|
});
|
|
385
397
|
build.onDispose(() => {
|
|
386
398
|
sharedTSCompilationState?.dispose();
|
|
387
|
-
void stylesheetBundler.dispose();
|
|
388
399
|
void compilation.close?.();
|
|
389
400
|
void cacheStore?.close();
|
|
390
401
|
});
|
|
@@ -405,17 +416,25 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
405
416
|
};
|
|
406
417
|
}
|
|
407
418
|
async function bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults) {
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
419
|
+
const styleResult = await stylesheetBundler.bundleFile(stylesheetFile, externalId);
|
|
420
|
+
(result.warnings ??= []).push(...styleResult.warnings);
|
|
421
|
+
if (styleResult.errors) {
|
|
422
|
+
(result.errors ??= []).push(...styleResult.errors);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
const { outputFiles, metafile } = styleResult;
|
|
426
|
+
// Clear inputs to prevent triggering a rebuild of the application code for component
|
|
427
|
+
// stylesheet file only changes when the dev server enables the internal-only external
|
|
428
|
+
// stylesheet option. This does not affect builds since only the dev server can enable
|
|
429
|
+
// the internal option.
|
|
430
|
+
metafile.inputs = {};
|
|
431
|
+
additionalResults.set(stylesheetFile, {
|
|
432
|
+
outputFiles,
|
|
433
|
+
metafile,
|
|
434
|
+
});
|
|
411
435
|
}
|
|
412
|
-
(result.warnings ??= []).push(...warnings);
|
|
413
|
-
additionalResults.set(stylesheetFile, {
|
|
414
|
-
outputFiles,
|
|
415
|
-
metafile,
|
|
416
|
-
});
|
|
417
436
|
}
|
|
418
|
-
function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks) {
|
|
437
|
+
function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, customConditions) {
|
|
419
438
|
return (compilerOptions) => {
|
|
420
439
|
// target of 9 is ES2022 (using the number avoids an expensive import of typescript just for an enum)
|
|
421
440
|
if (compilerOptions.target === undefined || compilerOptions.target < 9 /** ES2022 */) {
|
|
@@ -463,6 +482,11 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
|
|
|
463
482
|
notes: [{ text: `The 'module' option will be set to 'ES2022' instead.` }],
|
|
464
483
|
});
|
|
465
484
|
}
|
|
485
|
+
// Synchronize custom resolve conditions.
|
|
486
|
+
// Set if using the supported bundler resolution mode (bundler is the default in new projects)
|
|
487
|
+
if (compilerOptions.moduleResolution === 100 /* ModuleResolutionKind.Bundler */) {
|
|
488
|
+
compilerOptions.customConditions = customConditions;
|
|
489
|
+
}
|
|
466
490
|
return {
|
|
467
491
|
...compilerOptions,
|
|
468
492
|
noEmitOnError: false,
|
|
@@ -473,6 +497,7 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
|
|
|
473
497
|
sourceRoot: undefined,
|
|
474
498
|
preserveSymlinks,
|
|
475
499
|
externalRuntimeStyles: pluginOptions.externalRuntimeStyles,
|
|
500
|
+
_enableHmr: !!pluginOptions.templateUpdates,
|
|
476
501
|
};
|
|
477
502
|
};
|
|
478
503
|
}
|
|
@@ -5,8 +5,12 @@
|
|
|
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.dev/license
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { BundleContextResult } from '../bundler-context';
|
|
9
9
|
import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
|
|
10
|
+
export type ComponentStylesheetResult = BundleContextResult & {
|
|
11
|
+
contents: string;
|
|
12
|
+
referencedFiles: Set<string> | undefined;
|
|
13
|
+
};
|
|
10
14
|
/**
|
|
11
15
|
* Bundles component stylesheets. A stylesheet can be either an inline stylesheet that
|
|
12
16
|
* is contained within the Component's metadata definition or an external file referenced
|
|
@@ -15,35 +19,31 @@ import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
|
|
|
15
19
|
export declare class ComponentStylesheetBundler {
|
|
16
20
|
#private;
|
|
17
21
|
private readonly options;
|
|
22
|
+
private readonly defaultInlineLanguage;
|
|
18
23
|
private readonly incremental;
|
|
19
24
|
/**
|
|
20
25
|
*
|
|
21
26
|
* @param options An object containing the stylesheet bundling options.
|
|
22
27
|
* @param cache A load result cache to use when bundling.
|
|
23
28
|
*/
|
|
24
|
-
constructor(options: BundleStylesheetOptions, incremental: boolean);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
warnings: import("esbuild").Message[];
|
|
36
|
-
contents: string;
|
|
37
|
-
outputFiles: OutputFile[];
|
|
38
|
-
metafile: import("esbuild").Metafile | undefined;
|
|
39
|
-
referencedFiles: Set<string> | undefined;
|
|
40
|
-
}>;
|
|
29
|
+
constructor(options: BundleStylesheetOptions, defaultInlineLanguage: string, incremental: boolean);
|
|
30
|
+
/**
|
|
31
|
+
* Bundle a file-based component stylesheet for use within an AOT compiled Angular application.
|
|
32
|
+
* @param entry The file path of the stylesheet.
|
|
33
|
+
* @param externalId Either an external identifier string for initial bundling or a boolean for rebuilds, if external.
|
|
34
|
+
* @param direct If true, the output will be used directly by the builder; false if used inside the compiler plugin.
|
|
35
|
+
* @returns A component bundle result object.
|
|
36
|
+
*/
|
|
37
|
+
bundleFile(entry: string, externalId?: string | boolean, direct?: boolean): Promise<ComponentStylesheetResult>;
|
|
38
|
+
bundleAllFiles(external: boolean, direct: boolean): Promise<ComponentStylesheetResult[]>;
|
|
39
|
+
bundleInline(data: string, filename: string, language?: string, externalId?: string): Promise<ComponentStylesheetResult>;
|
|
41
40
|
/**
|
|
42
41
|
* Invalidates both file and inline based component style bundling state for a set of modified files.
|
|
43
42
|
* @param files The group of files that have been modified
|
|
44
43
|
* @returns An array of file based stylesheet entries if any were invalidated; otherwise, undefined.
|
|
45
44
|
*/
|
|
46
45
|
invalidate(files: Iterable<string>): string[] | undefined;
|
|
46
|
+
collectReferencedFiles(): string[];
|
|
47
47
|
dispose(): Promise<void>;
|
|
48
48
|
private extractResult;
|
|
49
49
|
}
|
|
@@ -24,6 +24,7 @@ const bundle_options_1 = require("../stylesheets/bundle-options");
|
|
|
24
24
|
*/
|
|
25
25
|
class ComponentStylesheetBundler {
|
|
26
26
|
options;
|
|
27
|
+
defaultInlineLanguage;
|
|
27
28
|
incremental;
|
|
28
29
|
#fileContexts = new cache_1.MemoryCache();
|
|
29
30
|
#inlineContexts = new cache_1.MemoryCache();
|
|
@@ -32,17 +33,26 @@ class ComponentStylesheetBundler {
|
|
|
32
33
|
* @param options An object containing the stylesheet bundling options.
|
|
33
34
|
* @param cache A load result cache to use when bundling.
|
|
34
35
|
*/
|
|
35
|
-
constructor(options, incremental) {
|
|
36
|
+
constructor(options, defaultInlineLanguage, incremental) {
|
|
36
37
|
this.options = options;
|
|
38
|
+
this.defaultInlineLanguage = defaultInlineLanguage;
|
|
37
39
|
this.incremental = incremental;
|
|
38
40
|
}
|
|
39
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Bundle a file-based component stylesheet for use within an AOT compiled Angular application.
|
|
43
|
+
* @param entry The file path of the stylesheet.
|
|
44
|
+
* @param externalId Either an external identifier string for initial bundling or a boolean for rebuilds, if external.
|
|
45
|
+
* @param direct If true, the output will be used directly by the builder; false if used inside the compiler plugin.
|
|
46
|
+
* @returns A component bundle result object.
|
|
47
|
+
*/
|
|
48
|
+
async bundleFile(entry, externalId, direct) {
|
|
40
49
|
const bundlerContext = await this.#fileContexts.getOrCreate(entry, () => {
|
|
41
50
|
return new bundler_context_1.BundlerContext(this.options.workspaceRoot, this.incremental, (loadCache) => {
|
|
42
51
|
const buildOptions = (0, bundle_options_1.createStylesheetBundleOptions)(this.options, loadCache);
|
|
43
52
|
if (externalId) {
|
|
44
53
|
(0, node_assert_1.default)(typeof externalId === 'string', 'Initial external component stylesheets must have a string identifier');
|
|
45
54
|
buildOptions.entryPoints = { [externalId]: entry };
|
|
55
|
+
buildOptions.entryNames = '[name]';
|
|
46
56
|
delete buildOptions.publicPath;
|
|
47
57
|
}
|
|
48
58
|
else {
|
|
@@ -51,9 +61,12 @@ class ComponentStylesheetBundler {
|
|
|
51
61
|
return buildOptions;
|
|
52
62
|
});
|
|
53
63
|
});
|
|
54
|
-
return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId);
|
|
64
|
+
return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId, !!direct);
|
|
55
65
|
}
|
|
56
|
-
|
|
66
|
+
bundleAllFiles(external, direct) {
|
|
67
|
+
return Promise.all(Array.from(this.#fileContexts.entries()).map(([entry]) => this.bundleFile(entry, external, direct)));
|
|
68
|
+
}
|
|
69
|
+
async bundleInline(data, filename, language = this.defaultInlineLanguage, externalId) {
|
|
57
70
|
// Use a hash of the inline stylesheet content to ensure a consistent identifier. External stylesheets will resolve
|
|
58
71
|
// to the actual stylesheet file path.
|
|
59
72
|
// TODO: Consider xxhash instead for hashing
|
|
@@ -70,6 +83,7 @@ class ComponentStylesheetBundler {
|
|
|
70
83
|
});
|
|
71
84
|
if (externalId) {
|
|
72
85
|
buildOptions.entryPoints = { [externalId]: `${namespace};${entry}` };
|
|
86
|
+
buildOptions.entryNames = '[name]';
|
|
73
87
|
delete buildOptions.publicPath;
|
|
74
88
|
}
|
|
75
89
|
else {
|
|
@@ -100,7 +114,7 @@ class ComponentStylesheetBundler {
|
|
|
100
114
|
});
|
|
101
115
|
});
|
|
102
116
|
// Extract the result of the bundling from the output files
|
|
103
|
-
return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId);
|
|
117
|
+
return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId, false);
|
|
104
118
|
}
|
|
105
119
|
/**
|
|
106
120
|
* Invalidates both file and inline based component style bundling state for a set of modified files.
|
|
@@ -124,61 +138,75 @@ class ComponentStylesheetBundler {
|
|
|
124
138
|
}
|
|
125
139
|
return entries;
|
|
126
140
|
}
|
|
141
|
+
collectReferencedFiles() {
|
|
142
|
+
const files = [];
|
|
143
|
+
for (const context of this.#fileContexts.values()) {
|
|
144
|
+
files.push(...context.watchFiles);
|
|
145
|
+
}
|
|
146
|
+
return files;
|
|
147
|
+
}
|
|
127
148
|
async dispose() {
|
|
128
149
|
const contexts = [...this.#fileContexts.values(), ...this.#inlineContexts.values()];
|
|
129
150
|
this.#fileContexts.clear();
|
|
130
151
|
this.#inlineContexts.clear();
|
|
131
152
|
await Promise.allSettled(contexts.map((context) => context.dispose()));
|
|
132
153
|
}
|
|
133
|
-
extractResult(result, referencedFiles, external) {
|
|
154
|
+
extractResult(result, referencedFiles, external, direct) {
|
|
134
155
|
let contents = '';
|
|
135
|
-
let metafile;
|
|
136
156
|
const outputFiles = [];
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
const { errors, warnings } = result;
|
|
158
|
+
if (errors) {
|
|
159
|
+
return { errors, warnings, referencedFiles, contents: '' };
|
|
160
|
+
}
|
|
161
|
+
for (const outputFile of result.outputFiles) {
|
|
162
|
+
const filename = node_path_1.default.basename(outputFile.path);
|
|
163
|
+
if (outputFile.type === bundler_context_1.BuildOutputFileType.Media || filename.endsWith('.css.map')) {
|
|
164
|
+
// The output files could also contain resources (images/fonts/etc.) that were referenced and the map files.
|
|
165
|
+
// Clone the output file to avoid amending the original path which would causes problems during rebuild.
|
|
166
|
+
const clonedOutputFile = outputFile.clone();
|
|
167
|
+
// Needed for Bazel as otherwise the files will not be written in the correct place,
|
|
168
|
+
// this is because esbuild will resolve the output file from the outdir which is currently set to `workspaceRoot` twice,
|
|
169
|
+
// once in the stylesheet and the other in the application code bundler.
|
|
170
|
+
// Ex: `../../../../../app.component.css.map`.
|
|
171
|
+
if (!direct) {
|
|
148
172
|
clonedOutputFile.path = node_path_1.default.join(this.options.workspaceRoot, outputFile.path);
|
|
149
|
-
outputFiles.push(clonedOutputFile);
|
|
150
173
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
174
|
+
outputFiles.push(clonedOutputFile);
|
|
175
|
+
}
|
|
176
|
+
else if (filename.endsWith('.css')) {
|
|
177
|
+
if (external) {
|
|
178
|
+
const clonedOutputFile = outputFile.clone();
|
|
179
|
+
if (!direct) {
|
|
154
180
|
clonedOutputFile.path = node_path_1.default.join(this.options.workspaceRoot, outputFile.path);
|
|
155
|
-
outputFiles.push(clonedOutputFile);
|
|
156
|
-
contents = node_path_1.default.posix.join(this.options.publicPath ?? '', filename);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
contents = outputFile.text;
|
|
160
181
|
}
|
|
182
|
+
outputFiles.push(clonedOutputFile);
|
|
183
|
+
contents = node_path_1.default.posix.join(this.options.publicPath ?? '', filename);
|
|
161
184
|
}
|
|
162
185
|
else {
|
|
163
|
-
|
|
186
|
+
contents = outputFile.text;
|
|
164
187
|
}
|
|
165
188
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Object.values(metafile.outputs).forEach((output) => {
|
|
170
|
-
delete output.entryPoint;
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
-
output['ng-component'] = true;
|
|
173
|
-
});
|
|
189
|
+
else {
|
|
190
|
+
throw new Error(`Unexpected non CSS/Media file "${filename}" outputted during component stylesheet processing.`);
|
|
191
|
+
}
|
|
174
192
|
}
|
|
193
|
+
const metafile = result.metafile;
|
|
194
|
+
// Remove entryPoint fields from outputs to prevent the internal component styles from being
|
|
195
|
+
// treated as initial files. Also mark the entry as a component resource for stat reporting.
|
|
196
|
+
Object.values(metafile.outputs).forEach((output) => {
|
|
197
|
+
delete output.entryPoint;
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
|
+
output['ng-component'] = true;
|
|
200
|
+
});
|
|
175
201
|
return {
|
|
176
|
-
errors
|
|
177
|
-
warnings
|
|
202
|
+
errors,
|
|
203
|
+
warnings,
|
|
178
204
|
contents,
|
|
179
205
|
outputFiles,
|
|
180
206
|
metafile,
|
|
181
207
|
referencedFiles,
|
|
208
|
+
externalImports: result.externalImports,
|
|
209
|
+
initialFiles: new Map(),
|
|
182
210
|
};
|
|
183
211
|
}
|
|
184
212
|
}
|
|
@@ -20,4 +20,4 @@ import { ComponentStylesheetBundler } from './component-stylesheets';
|
|
|
20
20
|
export declare function setupJitPluginCallbacks(build: PluginBuild, stylesheetBundler: ComponentStylesheetBundler, additionalResultFiles: Map<string, {
|
|
21
21
|
outputFiles?: OutputFile[];
|
|
22
22
|
metafile?: Metafile;
|
|
23
|
-
}>,
|
|
23
|
+
}>, loadCache?: LoadResultCache): void;
|
|
@@ -51,7 +51,7 @@ async function loadEntry(entry, root, skipRead) {
|
|
|
51
51
|
* @param styleOptions The options to use when bundling stylesheets.
|
|
52
52
|
* @param additionalResultFiles A Map where stylesheet resources will be added.
|
|
53
53
|
*/
|
|
54
|
-
function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles,
|
|
54
|
+
function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles, loadCache) {
|
|
55
55
|
const root = build.initialOptions.absWorkingDir ?? '';
|
|
56
56
|
// Add a resolve callback to capture and parse any JIT URIs that were added by the
|
|
57
57
|
// JIT resource TypeScript transformer.
|
|
@@ -90,9 +90,17 @@ function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles
|
|
|
90
90
|
stylesheetResult = await stylesheetBundler.bundleFile(entry.path);
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
93
|
-
stylesheetResult = await stylesheetBundler.bundleInline(entry.contents, entry.path
|
|
93
|
+
stylesheetResult = await stylesheetBundler.bundleInline(entry.contents, entry.path);
|
|
94
94
|
}
|
|
95
|
-
const {
|
|
95
|
+
const { errors, warnings, referencedFiles } = stylesheetResult;
|
|
96
|
+
if (stylesheetResult.errors) {
|
|
97
|
+
return {
|
|
98
|
+
errors,
|
|
99
|
+
warnings,
|
|
100
|
+
watchFiles: referencedFiles && [...referencedFiles],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const { contents, outputFiles, metafile } = stylesheetResult;
|
|
96
104
|
additionalResultFiles.set(entry.path, { outputFiles, metafile });
|
|
97
105
|
return {
|
|
98
106
|
errors,
|
|
@@ -14,5 +14,5 @@ export declare class SourceFileCache extends Map<string, ts.SourceFile> {
|
|
|
14
14
|
readonly loadResultCache: MemoryLoadResultCache;
|
|
15
15
|
referencedFiles?: readonly string[];
|
|
16
16
|
constructor(persistentCachePath?: string | undefined);
|
|
17
|
-
invalidate(files: Iterable<string>):
|
|
17
|
+
invalidate(files: Iterable<string>): boolean;
|
|
18
18
|
}
|
|
@@ -50,16 +50,20 @@ class SourceFileCache extends Map {
|
|
|
50
50
|
if (files !== this.modifiedFiles) {
|
|
51
51
|
this.modifiedFiles.clear();
|
|
52
52
|
}
|
|
53
|
+
const extraWatchFiles = new Set(this.referencedFiles?.map(path.normalize));
|
|
54
|
+
let invalid = false;
|
|
53
55
|
for (let file of files) {
|
|
54
56
|
file = path.normalize(file);
|
|
55
|
-
this.loadResultCache.invalidate(file);
|
|
57
|
+
invalid = this.loadResultCache.invalidate(file) || invalid;
|
|
58
|
+
invalid = extraWatchFiles.has(file) || invalid;
|
|
56
59
|
// Normalize separators to allow matching TypeScript Host paths
|
|
57
60
|
if (USING_WINDOWS) {
|
|
58
61
|
file = file.replace(WINDOWS_SEP_REGEXP, path.posix.sep);
|
|
59
62
|
}
|
|
60
|
-
this.delete(file);
|
|
63
|
+
invalid = this.delete(file) || invalid;
|
|
61
64
|
this.modifiedFiles.add(file);
|
|
62
65
|
}
|
|
66
|
+
return invalid;
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
exports.SourceFileCache = SourceFileCache;
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { BuildOptions } from 'esbuild';
|
|
9
9
|
import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
10
|
+
import { ComponentStylesheetBundler } from './angular/component-stylesheets';
|
|
10
11
|
import { SourceFileCache } from './angular/source-file-cache';
|
|
11
12
|
import { BundlerOptionsFactory } from './bundler-context';
|
|
12
|
-
|
|
13
|
-
export declare function
|
|
14
|
-
export declare function
|
|
15
|
-
export declare function
|
|
16
|
-
export declare function
|
|
13
|
+
import type { LoadResultCache } from './load-result-cache';
|
|
14
|
+
export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler, templateUpdates: Map<string, string> | undefined): BundlerOptionsFactory;
|
|
15
|
+
export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions | BundlerOptionsFactory | undefined;
|
|
16
|
+
export declare function createServerPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], loadResultCache: LoadResultCache | undefined): BundlerOptionsFactory | undefined;
|
|
17
|
+
export declare function createServerMainCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BundlerOptionsFactory;
|
|
18
|
+
export declare function createSsrEntryCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BundlerOptionsFactory;
|