@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
|
@@ -58,10 +58,11 @@ export declare class BundlerContext {
|
|
|
58
58
|
* All builds use the `write` option with a value of `false` to allow for the output files
|
|
59
59
|
* build result array to be populated.
|
|
60
60
|
*
|
|
61
|
+
* @param force If true, always rebundle.
|
|
61
62
|
* @returns If output files are generated, the full esbuild BuildResult; if not, the
|
|
62
63
|
* warnings and errors for the attempted build.
|
|
63
64
|
*/
|
|
64
|
-
bundle(): Promise<BundleContextResult>;
|
|
65
|
+
bundle(force?: boolean): Promise<BundleContextResult>;
|
|
65
66
|
/**
|
|
66
67
|
* Invalidate a stored bundler result based on the previous watch files
|
|
67
68
|
* and a list of changed files.
|
|
@@ -125,12 +125,13 @@ class BundlerContext {
|
|
|
125
125
|
* All builds use the `write` option with a value of `false` to allow for the output files
|
|
126
126
|
* build result array to be populated.
|
|
127
127
|
*
|
|
128
|
+
* @param force If true, always rebundle.
|
|
128
129
|
* @returns If output files are generated, the full esbuild BuildResult; if not, the
|
|
129
130
|
* warnings and errors for the attempted build.
|
|
130
131
|
*/
|
|
131
|
-
async bundle() {
|
|
132
|
+
async bundle(force) {
|
|
132
133
|
// Return existing result if present
|
|
133
|
-
if (this.#esbuildResult) {
|
|
134
|
+
if (!force && this.#esbuildResult) {
|
|
134
135
|
return this.#esbuildResult;
|
|
135
136
|
}
|
|
136
137
|
const result = await this.#performBundle();
|
|
@@ -211,6 +212,7 @@ class BundlerContext {
|
|
|
211
212
|
warnings: result.warnings,
|
|
212
213
|
};
|
|
213
214
|
}
|
|
215
|
+
const { 'ng-platform-server': isPlatformServer = false, 'ng-ssr-entry-bundle': isSsrEntryBundle = false, } = result.metafile;
|
|
214
216
|
// Find all initial files
|
|
215
217
|
const initialFiles = new Map();
|
|
216
218
|
for (const outputFile of result.outputFiles) {
|
|
@@ -231,7 +233,7 @@ class BundlerContext {
|
|
|
231
233
|
name,
|
|
232
234
|
type,
|
|
233
235
|
entrypoint: true,
|
|
234
|
-
serverFile:
|
|
236
|
+
serverFile: isPlatformServer,
|
|
235
237
|
depth: 0,
|
|
236
238
|
};
|
|
237
239
|
if (!this.initialFilter || this.initialFilter(record)) {
|
|
@@ -259,7 +261,7 @@ class BundlerContext {
|
|
|
259
261
|
type: initialImport.kind === 'import-rule' ? 'style' : 'script',
|
|
260
262
|
entrypoint: false,
|
|
261
263
|
external: initialImport.external,
|
|
262
|
-
serverFile:
|
|
264
|
+
serverFile: isPlatformServer,
|
|
263
265
|
depth: entryRecord.depth + 1,
|
|
264
266
|
};
|
|
265
267
|
if (!this.initialFilter || this.initialFilter(record)) {
|
|
@@ -292,9 +294,8 @@ class BundlerContext {
|
|
|
292
294
|
if (!/\.([cm]?js|css|wasm)(\.map)?$/i.test(file.path)) {
|
|
293
295
|
fileType = BuildOutputFileType.Media;
|
|
294
296
|
}
|
|
295
|
-
else if (
|
|
296
|
-
|
|
297
|
-
fileType = result.metafile['ng-ssr-entry-bundle']
|
|
297
|
+
else if (isPlatformServer) {
|
|
298
|
+
fileType = isSsrEntryBundle
|
|
298
299
|
? BuildOutputFileType.ServerRoot
|
|
299
300
|
: BuildOutputFileType.ServerApplication;
|
|
300
301
|
}
|
|
@@ -304,7 +305,7 @@ class BundlerContext {
|
|
|
304
305
|
return (0, utils_1.convertOutputFile)(file, fileType);
|
|
305
306
|
});
|
|
306
307
|
let externalConfiguration = this.#esbuildOptions.external;
|
|
307
|
-
if (
|
|
308
|
+
if (isPlatformServer && externalConfiguration) {
|
|
308
309
|
externalConfiguration = externalConfiguration.filter((dep) => !utils_1.SERVER_GENERATED_EXTERNALS.has(dep));
|
|
309
310
|
if (!externalConfiguration.length) {
|
|
310
311
|
externalConfiguration = undefined;
|
|
@@ -316,7 +317,7 @@ class BundlerContext {
|
|
|
316
317
|
outputFiles,
|
|
317
318
|
initialFiles,
|
|
318
319
|
externalImports: {
|
|
319
|
-
[
|
|
320
|
+
[isPlatformServer ? 'server' : 'browser']: externalImports,
|
|
320
321
|
},
|
|
321
322
|
externalConfiguration,
|
|
322
323
|
errors: undefined,
|
|
@@ -336,9 +337,6 @@ class BundlerContext {
|
|
|
336
337
|
}
|
|
337
338
|
}
|
|
338
339
|
}
|
|
339
|
-
get #platformIsServer() {
|
|
340
|
-
return this.#esbuildOptions?.platform === 'node';
|
|
341
|
-
}
|
|
342
340
|
/**
|
|
343
341
|
* Invalidate a stored bundler result based on the previous watch files
|
|
344
342
|
* and a list of changed files.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Message, PartialMessage } from 'esbuild';
|
|
9
9
|
import type { ChangedFiles } from '../../tools/esbuild/watcher';
|
|
10
|
+
import type { ComponentStylesheetBundler } from './angular/component-stylesheets';
|
|
10
11
|
import type { SourceFileCache } from './angular/source-file-cache';
|
|
11
12
|
import type { BuildOutputFile, BuildOutputFileType, BundlerContext } from './bundler-context';
|
|
12
13
|
export interface BuildOutputAsset {
|
|
@@ -14,10 +15,15 @@ export interface BuildOutputAsset {
|
|
|
14
15
|
destination: string;
|
|
15
16
|
}
|
|
16
17
|
export interface RebuildState {
|
|
17
|
-
rebuildContexts:
|
|
18
|
+
rebuildContexts: {
|
|
19
|
+
typescriptContexts: BundlerContext[];
|
|
20
|
+
otherContexts: BundlerContext[];
|
|
21
|
+
};
|
|
22
|
+
componentStyleBundler: ComponentStylesheetBundler;
|
|
18
23
|
codeBundleCache?: SourceFileCache;
|
|
19
24
|
fileChanges: ChangedFiles;
|
|
20
25
|
previousOutputHashes: Map<string, string>;
|
|
26
|
+
templateUpdates?: Map<string, string>;
|
|
21
27
|
}
|
|
22
28
|
export interface ExternalResultMetadata {
|
|
23
29
|
implicitBrowser: string[];
|
|
@@ -32,7 +38,9 @@ export type PrerenderedRoutesRecord = Record<string, {
|
|
|
32
38
|
*/
|
|
33
39
|
export declare class ExecutionResult {
|
|
34
40
|
private rebuildContexts;
|
|
41
|
+
private componentStyleBundler;
|
|
35
42
|
private codeBundleCache?;
|
|
43
|
+
readonly templateUpdates?: Map<string, string> | undefined;
|
|
36
44
|
outputFiles: BuildOutputFile[];
|
|
37
45
|
assetFiles: BuildOutputAsset[];
|
|
38
46
|
errors: (Message | PartialMessage)[];
|
|
@@ -43,7 +51,10 @@ export declare class ExecutionResult {
|
|
|
43
51
|
extraWatchFiles: string[];
|
|
44
52
|
htmlIndexPath?: string;
|
|
45
53
|
htmlBaseHref?: string;
|
|
46
|
-
constructor(rebuildContexts:
|
|
54
|
+
constructor(rebuildContexts: {
|
|
55
|
+
typescriptContexts: BundlerContext[];
|
|
56
|
+
otherContexts: BundlerContext[];
|
|
57
|
+
}, componentStyleBundler: ComponentStylesheetBundler, codeBundleCache?: SourceFileCache | undefined, templateUpdates?: Map<string, string> | undefined);
|
|
47
58
|
addOutputFile(path: string, content: string | Uint8Array, type: BuildOutputFileType): void;
|
|
48
59
|
addAssets(assets: BuildOutputAsset[]): void;
|
|
49
60
|
addLog(value: string): void;
|
|
@@ -67,7 +78,7 @@ export declare class ExecutionResult {
|
|
|
67
78
|
success: boolean;
|
|
68
79
|
outputFiles: BuildOutputFile[];
|
|
69
80
|
assetFiles: BuildOutputAsset[];
|
|
70
|
-
errors: (
|
|
81
|
+
errors: (PartialMessage | Message)[];
|
|
71
82
|
externalMetadata: ExternalResultMetadata | undefined;
|
|
72
83
|
};
|
|
73
84
|
get watchFiles(): string[];
|
|
@@ -15,7 +15,9 @@ const utils_1 = require("./utils");
|
|
|
15
15
|
*/
|
|
16
16
|
class ExecutionResult {
|
|
17
17
|
rebuildContexts;
|
|
18
|
+
componentStyleBundler;
|
|
18
19
|
codeBundleCache;
|
|
20
|
+
templateUpdates;
|
|
19
21
|
outputFiles = [];
|
|
20
22
|
assetFiles = [];
|
|
21
23
|
errors = [];
|
|
@@ -26,9 +28,11 @@ class ExecutionResult {
|
|
|
26
28
|
extraWatchFiles = [];
|
|
27
29
|
htmlIndexPath;
|
|
28
30
|
htmlBaseHref;
|
|
29
|
-
constructor(rebuildContexts, codeBundleCache) {
|
|
31
|
+
constructor(rebuildContexts, componentStyleBundler, codeBundleCache, templateUpdates) {
|
|
30
32
|
this.rebuildContexts = rebuildContexts;
|
|
33
|
+
this.componentStyleBundler = componentStyleBundler;
|
|
31
34
|
this.codeBundleCache = codeBundleCache;
|
|
35
|
+
this.templateUpdates = templateUpdates;
|
|
32
36
|
}
|
|
33
37
|
addOutputFile(path, content, type) {
|
|
34
38
|
this.outputFiles.push((0, utils_1.createOutputFile)(path, content, type));
|
|
@@ -100,25 +104,24 @@ class ExecutionResult {
|
|
|
100
104
|
}
|
|
101
105
|
get watchFiles() {
|
|
102
106
|
// Bundler contexts internally normalize file dependencies
|
|
103
|
-
const files = this.rebuildContexts.
|
|
107
|
+
const files = this.rebuildContexts.typescriptContexts
|
|
108
|
+
.flatMap((context) => [...context.watchFiles])
|
|
109
|
+
.concat(this.rebuildContexts.otherContexts.flatMap((context) => [...context.watchFiles]));
|
|
104
110
|
if (this.codeBundleCache?.referencedFiles) {
|
|
105
111
|
// These files originate from TS/NG and can have POSIX path separators even on Windows.
|
|
106
112
|
// To ensure path comparisons are valid, all these paths must be normalized.
|
|
107
113
|
files.push(...this.codeBundleCache.referencedFiles.map(node_path_1.normalize));
|
|
108
114
|
}
|
|
109
|
-
if (this.codeBundleCache?.loadResultCache) {
|
|
110
|
-
// Load result caches internally normalize file dependencies
|
|
111
|
-
files.push(...this.codeBundleCache.loadResultCache.watchFiles);
|
|
112
|
-
}
|
|
113
115
|
return files.concat(this.extraWatchFiles);
|
|
114
116
|
}
|
|
115
117
|
createRebuildState(fileChanges) {
|
|
116
|
-
this.codeBundleCache?.invalidate([...fileChanges.modified, ...fileChanges.removed]);
|
|
117
118
|
return {
|
|
118
119
|
rebuildContexts: this.rebuildContexts,
|
|
119
120
|
codeBundleCache: this.codeBundleCache,
|
|
121
|
+
componentStyleBundler: this.componentStyleBundler,
|
|
120
122
|
fileChanges,
|
|
121
123
|
previousOutputHashes: new Map(this.outputFiles.map((file) => [file.path, file.hash])),
|
|
124
|
+
templateUpdates: this.templateUpdates,
|
|
122
125
|
};
|
|
123
126
|
}
|
|
124
127
|
findChangedFiles(previousOutputHashes) {
|
|
@@ -132,7 +135,11 @@ class ExecutionResult {
|
|
|
132
135
|
return changed;
|
|
133
136
|
}
|
|
134
137
|
async dispose() {
|
|
135
|
-
await Promise.allSettled(
|
|
138
|
+
await Promise.allSettled([
|
|
139
|
+
...this.rebuildContexts.typescriptContexts.map((context) => context.dispose()),
|
|
140
|
+
...this.rebuildContexts.otherContexts.map((context) => context.dispose()),
|
|
141
|
+
this.componentStyleBundler.dispose(),
|
|
142
|
+
]);
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
145
|
exports.ExecutionResult = ExecutionResult;
|
|
@@ -42,9 +42,9 @@ function checkCommonJSModules(metafile, allowedCommonJsDependencies) {
|
|
|
42
42
|
// using `provideHttpClient(withFetch())`.
|
|
43
43
|
allowedRequests.add('xhr2');
|
|
44
44
|
// Packages used by @angular/ssr.
|
|
45
|
-
// While
|
|
45
|
+
// While beasties is ESM it has a number of direct and transtive CJS deps.
|
|
46
46
|
allowedRequests.add('express');
|
|
47
|
-
allowedRequests.add('
|
|
47
|
+
allowedRequests.add('beasties');
|
|
48
48
|
// Find all entry points that contain code (JS/TS)
|
|
49
49
|
const files = [];
|
|
50
50
|
for (const { entryPoint } of Object.values(metafile.outputs)) {
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
import { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
9
9
|
import type { createCompilerPlugin } from './angular/compiler-plugin';
|
|
10
10
|
import type { SourceFileCache } from './angular/source-file-cache';
|
|
11
|
+
import type { LoadResultCache } from './load-result-cache';
|
|
11
12
|
type CreateCompilerPluginParameters = Parameters<typeof createCompilerPlugin>;
|
|
12
|
-
export declare function createCompilerPluginOptions(options: NormalizedApplicationBuildOptions,
|
|
13
|
-
pluginOptions: CreateCompilerPluginParameters[0];
|
|
14
|
-
styleOptions: CreateCompilerPluginParameters[1];
|
|
15
|
-
};
|
|
13
|
+
export declare function createCompilerPluginOptions(options: NormalizedApplicationBuildOptions, sourceFileCache: SourceFileCache, loadResultCache?: LoadResultCache, templateUpdates?: Map<string, string>): CreateCompilerPluginParameters[0];
|
|
16
14
|
export {};
|
|
@@ -8,43 +8,21 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.createCompilerPluginOptions = createCompilerPluginOptions;
|
|
11
|
-
function createCompilerPluginOptions(options,
|
|
12
|
-
const {
|
|
11
|
+
function createCompilerPluginOptions(options, sourceFileCache, loadResultCache, templateUpdates) {
|
|
12
|
+
const { sourcemapOptions, tsconfig, fileReplacements, advancedOptimizations, jit, externalRuntimeStyles, instrumentForCoverage, } = options;
|
|
13
|
+
const incremental = !!options.watch;
|
|
13
14
|
return {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
instrumentForCoverage,
|
|
27
|
-
},
|
|
28
|
-
// Component stylesheet options
|
|
29
|
-
styleOptions: {
|
|
30
|
-
workspaceRoot,
|
|
31
|
-
inlineFonts: !!optimizationOptions.fonts.inline,
|
|
32
|
-
optimization: !!optimizationOptions.styles.minify,
|
|
33
|
-
sourcemap:
|
|
34
|
-
// Hidden component stylesheet sourcemaps are inaccessible which is effectively
|
|
35
|
-
// the same as being disabled. Disabling has the advantage of avoiding the overhead
|
|
36
|
-
// of sourcemap processing.
|
|
37
|
-
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
|
|
38
|
-
outputNames,
|
|
39
|
-
includePaths: stylePreprocessorOptions?.includePaths,
|
|
40
|
-
externalDependencies,
|
|
41
|
-
target,
|
|
42
|
-
inlineStyleLanguage,
|
|
43
|
-
preserveSymlinks,
|
|
44
|
-
tailwindConfiguration,
|
|
45
|
-
postcssConfiguration,
|
|
46
|
-
cacheOptions,
|
|
47
|
-
publicPath,
|
|
48
|
-
},
|
|
15
|
+
sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
16
|
+
thirdPartySourcemaps: sourcemapOptions.vendor,
|
|
17
|
+
tsconfig,
|
|
18
|
+
jit,
|
|
19
|
+
advancedOptimizations,
|
|
20
|
+
fileReplacements,
|
|
21
|
+
sourceFileCache,
|
|
22
|
+
loadResultCache,
|
|
23
|
+
incremental,
|
|
24
|
+
externalRuntimeStyles,
|
|
25
|
+
instrumentForCoverage,
|
|
26
|
+
templateUpdates,
|
|
49
27
|
};
|
|
50
28
|
}
|
|
@@ -72,7 +72,7 @@ function createGlobalScriptsBundleOptions(options, target, initial) {
|
|
|
72
72
|
entryNames: initial ? outputNames.bundles : '[name]',
|
|
73
73
|
assetNames: outputNames.media,
|
|
74
74
|
mainFields: ['script', 'browser', 'main'],
|
|
75
|
-
conditions: ['script'],
|
|
75
|
+
conditions: ['script', optimizationOptions.scripts ? 'production' : 'development'],
|
|
76
76
|
resolveExtensions: ['.mjs', '.js', '.cjs'],
|
|
77
77
|
logLevel: options.verbose && !jsonLogs ? 'debug' : 'silent',
|
|
78
78
|
metafile: true,
|
|
@@ -45,12 +45,15 @@ function createGlobalStylesBundleOptions(options, target, initial) {
|
|
|
45
45
|
bundles: '[name]',
|
|
46
46
|
},
|
|
47
47
|
includePaths: stylePreprocessorOptions?.includePaths,
|
|
48
|
+
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
sass: stylePreprocessorOptions?.sass,
|
|
48
51
|
tailwindConfiguration,
|
|
49
52
|
postcssConfiguration,
|
|
50
53
|
cacheOptions,
|
|
51
54
|
}, loadCache);
|
|
52
55
|
// Keep special CSS comments `/*! comment */` in place when `removeSpecialComments` is disabled.
|
|
53
|
-
// These comments are special for a number of CSS tools such as
|
|
56
|
+
// These comments are special for a number of CSS tools such as Beasties and PurgeCSS.
|
|
54
57
|
buildOptions.legalComments = optimizationOptions.styles?.removeSpecialComments
|
|
55
58
|
? 'none'
|
|
56
59
|
: 'inline';
|
|
@@ -59,6 +59,13 @@ async function generateIndexHtml(initialFiles, outputFiles, buildOptions, lang)
|
|
|
59
59
|
}
|
|
60
60
|
throw new Error(`Output file does not exist: ${relativefilePath}`);
|
|
61
61
|
};
|
|
62
|
+
// Read the Auto CSP options.
|
|
63
|
+
const autoCsp = buildOptions.security?.autoCsp;
|
|
64
|
+
const autoCspOptions = autoCsp === true
|
|
65
|
+
? { unsafeEval: false }
|
|
66
|
+
: autoCsp
|
|
67
|
+
? { unsafeEval: !!autoCsp.unsafeEval }
|
|
68
|
+
: undefined;
|
|
62
69
|
// Create an index HTML generator that reads from the in-memory output files
|
|
63
70
|
const indexHtmlGenerator = new index_html_generator_1.IndexHtmlGenerator({
|
|
64
71
|
indexPath: indexHtmlOptions.input,
|
|
@@ -71,6 +78,7 @@ async function generateIndexHtml(initialFiles, outputFiles, buildOptions, lang)
|
|
|
71
78
|
generateDedicatedSSRContent: !!(buildOptions.ssrOptions ||
|
|
72
79
|
buildOptions.prerenderOptions ||
|
|
73
80
|
buildOptions.appShellOptions),
|
|
81
|
+
autoCsp: autoCspOptions,
|
|
74
82
|
});
|
|
75
83
|
indexHtmlGenerator.readAsset = readAsset;
|
|
76
84
|
return indexHtmlGenerator.process({
|
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.JavaScriptTransformer = void 0;
|
|
11
11
|
const node_crypto_1 = require("node:crypto");
|
|
12
12
|
const promises_1 = require("node:fs/promises");
|
|
13
|
+
const utils_1 = require("../../utils/server-rendering/esm-in-memory-loader/utils");
|
|
13
14
|
const worker_pool_1 = require("../../utils/worker-pool");
|
|
14
15
|
/**
|
|
15
16
|
* A class that performs transformation of JavaScript files and raw data.
|
|
@@ -41,6 +42,8 @@ class JavaScriptTransformer {
|
|
|
41
42
|
this.#workerPool ??= new worker_pool_1.WorkerPool({
|
|
42
43
|
filename: require.resolve('./javascript-transformer-worker'),
|
|
43
44
|
maxThreads: this.maxThreads,
|
|
45
|
+
// Prevent passing `--import` (loader-hooks) from parent to child worker.
|
|
46
|
+
execArgv: process.execArgv.filter((v) => v !== utils_1.IMPORT_EXEC_ARGV),
|
|
44
47
|
});
|
|
45
48
|
return this.#workerPool;
|
|
46
49
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Google LLC All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
7
|
+
*/
|
|
8
|
+
import type { Plugin } from 'esbuild';
|
|
9
|
+
/**
|
|
10
|
+
* Generates an esbuild plugin that appends metadata to the output bundle,
|
|
11
|
+
* marking it with server-side rendering (SSR) details for Angular SSR scenarios.
|
|
12
|
+
*
|
|
13
|
+
* @param options Optional configuration object.
|
|
14
|
+
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
15
|
+
*
|
|
16
|
+
* @remarks We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
17
|
+
* is used for non-SSR-related code too (e.g., global scripts).
|
|
18
|
+
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createServerBundleMetadata(options?: {
|
|
21
|
+
ssrEntryBundle?: boolean;
|
|
22
|
+
}): Plugin;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createServerBundleMetadata = createServerBundleMetadata;
|
|
11
|
+
/**
|
|
12
|
+
* Generates an esbuild plugin that appends metadata to the output bundle,
|
|
13
|
+
* marking it with server-side rendering (SSR) details for Angular SSR scenarios.
|
|
14
|
+
*
|
|
15
|
+
* @param options Optional configuration object.
|
|
16
|
+
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
17
|
+
*
|
|
18
|
+
* @remarks We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
19
|
+
* is used for non-SSR-related code too (e.g., global scripts).
|
|
20
|
+
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
21
|
+
*/
|
|
22
|
+
function createServerBundleMetadata(options) {
|
|
23
|
+
return {
|
|
24
|
+
name: 'angular-server-bundle-metadata',
|
|
25
|
+
setup(build) {
|
|
26
|
+
build.onEnd((result) => {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const metafile = result.metafile;
|
|
29
|
+
if (metafile) {
|
|
30
|
+
metafile['ng-ssr-entry-bundle'] = !!options?.ssrEntryBundle;
|
|
31
|
+
metafile['ng-platform-server'] = true;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -9,6 +9,7 @@ import type { BuildOptions } from 'esbuild';
|
|
|
9
9
|
import { NormalizedCachedOptions } from '../../../utils/normalize-cache';
|
|
10
10
|
import { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
|
11
11
|
import { LoadResultCache } from '../load-result-cache';
|
|
12
|
+
import { StylesheetPluginsass } from './stylesheet-plugin-factory';
|
|
12
13
|
export interface BundleStylesheetOptions {
|
|
13
14
|
workspaceRoot: string;
|
|
14
15
|
optimization: boolean;
|
|
@@ -20,6 +21,7 @@ export interface BundleStylesheetOptions {
|
|
|
20
21
|
media: string;
|
|
21
22
|
};
|
|
22
23
|
includePaths?: string[];
|
|
24
|
+
sass?: StylesheetPluginsass;
|
|
23
25
|
externalDependencies?: string[];
|
|
24
26
|
target: string[];
|
|
25
27
|
tailwindConfiguration?: {
|
|
@@ -27,6 +27,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
|
|
|
27
27
|
inlineComponentData,
|
|
28
28
|
tailwindConfiguration: options.tailwindConfiguration,
|
|
29
29
|
postcssConfiguration: options.postcssConfiguration,
|
|
30
|
+
sass: options.sass,
|
|
30
31
|
}, cache);
|
|
31
32
|
const plugins = [
|
|
32
33
|
pluginFactory.create(sass_language_1.SassStylesheetLanguage),
|
|
@@ -53,7 +54,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
|
|
|
53
54
|
preserveSymlinks: options.preserveSymlinks,
|
|
54
55
|
external: options.externalDependencies,
|
|
55
56
|
publicPath: options.publicPath,
|
|
56
|
-
conditions: ['style', 'sass', 'less'],
|
|
57
|
+
conditions: ['style', 'sass', 'less', options.optimization ? 'production' : 'development'],
|
|
57
58
|
mainFields: ['style', 'sass'],
|
|
58
59
|
// Unlike JS, CSS does not have implicit file extensions in the general case.
|
|
59
60
|
// Preprocessor specific behavior is handled in each stylesheet language plugin.
|
|
@@ -99,6 +99,7 @@ async function compileString(data, filePath, syntax, options, resolveUrl) {
|
|
|
99
99
|
const resolutionCache = new cache_1.MemoryCache();
|
|
100
100
|
const packageRootCache = new cache_1.MemoryCache();
|
|
101
101
|
const warnings = [];
|
|
102
|
+
const { silenceDeprecations, futureDeprecations, fatalDeprecations } = options.sass ?? {};
|
|
102
103
|
try {
|
|
103
104
|
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
|
|
104
105
|
url: (0, node_url_1.pathToFileURL)(filePath),
|
|
@@ -107,6 +108,9 @@ async function compileString(data, filePath, syntax, options, resolveUrl) {
|
|
|
107
108
|
loadPaths: options.includePaths,
|
|
108
109
|
sourceMap: options.sourcemap,
|
|
109
110
|
sourceMapIncludeSources: options.sourcemap,
|
|
111
|
+
silenceDeprecations,
|
|
112
|
+
fatalDeprecations,
|
|
113
|
+
futureDeprecations,
|
|
110
114
|
quietDeps: true,
|
|
111
115
|
importers: [
|
|
112
116
|
{
|
|
@@ -6,8 +6,13 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import type { OnLoadResult, Plugin, PluginBuild } from 'esbuild';
|
|
9
|
+
import type { Options } from 'sass';
|
|
9
10
|
import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
|
10
11
|
import { LoadResultCache } from '../load-result-cache';
|
|
12
|
+
/**
|
|
13
|
+
* Configuration options for handling Sass-specific deprecations in a stylesheet plugin.
|
|
14
|
+
*/
|
|
15
|
+
export type StylesheetPluginsass = Pick<Options<'async'>, 'futureDeprecations' | 'fatalDeprecations' | 'silenceDeprecations'>;
|
|
11
16
|
/**
|
|
12
17
|
* An object containing the plugin options to use when processing stylesheets.
|
|
13
18
|
*/
|
|
@@ -42,6 +47,10 @@ export interface StylesheetPluginOptions {
|
|
|
42
47
|
* and any tailwind usage must be manually configured in the custom postcss usage.
|
|
43
48
|
*/
|
|
44
49
|
postcssConfiguration?: PostcssConfiguration;
|
|
50
|
+
/**
|
|
51
|
+
* Optional Options for configuring Sass behavior.
|
|
52
|
+
*/
|
|
53
|
+
sass?: StylesheetPluginsass;
|
|
45
54
|
}
|
|
46
55
|
export interface StylesheetLanguage {
|
|
47
56
|
name: string;
|
|
@@ -38,6 +38,7 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
38
38
|
const browserStats = [];
|
|
39
39
|
const serverStats = [];
|
|
40
40
|
let unchangedCount = 0;
|
|
41
|
+
let componentStyleChange = false;
|
|
41
42
|
for (const { path: file, size, type } of outputFiles) {
|
|
42
43
|
// Only display JavaScript and CSS files
|
|
43
44
|
if (!/\.(?:css|m?js)$/.test(file)) {
|
|
@@ -53,6 +54,11 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
53
54
|
// Only log server build stats when SSR is enabled.
|
|
54
55
|
continue;
|
|
55
56
|
}
|
|
57
|
+
// Skip logging external component stylesheets used for HMR
|
|
58
|
+
if (metafile.outputs[file] && 'ng-component' in metafile.outputs[file]) {
|
|
59
|
+
componentStyleChange = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
56
62
|
const name = initial.get(file)?.name ?? getChunkNameFromMetafile(metafile, file);
|
|
57
63
|
const stat = {
|
|
58
64
|
initial: initial.has(file),
|
|
@@ -70,7 +76,12 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
70
76
|
return tableText + '\n';
|
|
71
77
|
}
|
|
72
78
|
else if (changedFiles !== undefined) {
|
|
73
|
-
|
|
79
|
+
if (componentStyleChange) {
|
|
80
|
+
return '\nComponent stylesheet(s) changed.\n';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return '\nNo output file changes.\n';
|
|
84
|
+
}
|
|
74
85
|
}
|
|
75
86
|
if (unchangedCount > 0) {
|
|
76
87
|
return `Unchanged output files: ${unchangedCount}`;
|
|
@@ -144,7 +155,7 @@ async function withNoProgress(text, action) {
|
|
|
144
155
|
* @returns An object that can be used with the esbuild build `supported` option.
|
|
145
156
|
*/
|
|
146
157
|
function getFeatureSupport(target, nativeAsyncAwait) {
|
|
147
|
-
|
|
158
|
+
return {
|
|
148
159
|
// Native async/await is not supported with Zone.js. Disabling support here will cause
|
|
149
160
|
// esbuild to downlevel async/await, async generators, and for await...of to a Zone.js supported form.
|
|
150
161
|
'async-await': nativeAsyncAwait,
|
|
@@ -154,35 +165,6 @@ function getFeatureSupport(target, nativeAsyncAwait) {
|
|
|
154
165
|
// For more details: https://bugs.chromium.org/p/v8/issues/detail?id=11536
|
|
155
166
|
'object-rest-spread': false,
|
|
156
167
|
};
|
|
157
|
-
// Detect Safari browser versions that have a class field behavior bug
|
|
158
|
-
// See: https://github.com/angular/angular-cli/issues/24355#issuecomment-1333477033
|
|
159
|
-
// See: https://github.com/WebKit/WebKit/commit/e8788a34b3d5f5b4edd7ff6450b80936bff396f2
|
|
160
|
-
let safariClassFieldScopeBug = false;
|
|
161
|
-
for (const browser of target) {
|
|
162
|
-
let majorVersion;
|
|
163
|
-
if (browser.startsWith('ios')) {
|
|
164
|
-
majorVersion = Number(browser.slice(3, 5));
|
|
165
|
-
}
|
|
166
|
-
else if (browser.startsWith('safari')) {
|
|
167
|
-
majorVersion = Number(browser.slice(6, 8));
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
// Technically, 14.0 is not broken but rather does not have support. However, the behavior
|
|
173
|
-
// is identical since it would be set to false by esbuild if present as a target.
|
|
174
|
-
if (majorVersion === 14 || majorVersion === 15) {
|
|
175
|
-
safariClassFieldScopeBug = true;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// If class field support cannot be used set to false; otherwise leave undefined to allow
|
|
180
|
-
// esbuild to use `target` to determine support.
|
|
181
|
-
if (safariClassFieldScopeBug) {
|
|
182
|
-
supported['class-field'] = false;
|
|
183
|
-
supported['class-static-field'] = false;
|
|
184
|
-
}
|
|
185
|
-
return supported;
|
|
186
168
|
}
|
|
187
169
|
const MAX_CONCURRENT_WRITES = 64;
|
|
188
170
|
async function emitFilesToDisk(files, writeFileCallback) {
|
package/src/tools/sass/worker.js
CHANGED
|
@@ -40,6 +40,25 @@ async function renderSassStylesheet(request) {
|
|
|
40
40
|
containingUrl: containingUrl ? (0, node_url_1.fileURLToPath)(containingUrl) : null,
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
|
+
// Wait for the main thread to set the signal to 1 and notify, which tells
|
|
44
|
+
// us that a message can be received on the port.
|
|
45
|
+
// If the main thread is fast, the signal will already be set to 1, and no
|
|
46
|
+
// sleep/notify is necessary.
|
|
47
|
+
// However, there can be a race condition here:
|
|
48
|
+
// - the main thread sets the signal to 1, but does not get to the notify instruction yet
|
|
49
|
+
// - the worker does not pause because the signal is set to 1
|
|
50
|
+
// - the worker very soon enters this method again
|
|
51
|
+
// - this method sets the signal to 0 and sends the message
|
|
52
|
+
// - the signal is 0 and so the `Atomics.wait` call blocks
|
|
53
|
+
// - only now the main thread runs the `notify` from the first invocation, so the
|
|
54
|
+
// worker continues.
|
|
55
|
+
// - but there is no message yet in the port, because the thread should not have been
|
|
56
|
+
// waken up yet.
|
|
57
|
+
// To combat this, wait for a non-0 value _twice_.
|
|
58
|
+
// Almost every time, this immediately continues with "not-equal", because
|
|
59
|
+
// the signal is still set to 1, except during the race condition, when the second
|
|
60
|
+
// wait will wait for the correct notify.
|
|
61
|
+
Atomics.wait(importerChannel.signal, 0, 0);
|
|
43
62
|
Atomics.wait(importerChannel.signal, 0, 0);
|
|
44
63
|
const result = (0, node_worker_threads_1.receiveMessageOnPort)(importerChannel.port)?.message;
|
|
45
64
|
return result ? (0, node_url_1.pathToFileURL)(result) : null;
|
|
@@ -7,4 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Connect, ViteDevServer } from 'vite';
|
|
9
9
|
import { AngularMemoryOutputFiles } from '../utils';
|
|
10
|
-
export
|
|
10
|
+
export interface ComponentStyleRecord {
|
|
11
|
+
rawContent: Uint8Array;
|
|
12
|
+
used?: Set<string>;
|
|
13
|
+
reload?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function createAngularAssetsMiddleware(server: ViteDevServer, assets: Map<string, string>, outputFiles: AngularMemoryOutputFiles, componentStyles: Map<string, ComponentStyleRecord>, encapsulateStyle: (style: Uint8Array, componentId: string) => string): Connect.NextHandleFunction;
|