@angular/build 19.0.0-next.0 → 19.0.0-next.10
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/LICENSE +5 -5
- package/package.json +20 -16
- package/src/builders/application/build-action.js +9 -9
- package/src/builders/application/chunk-optimizer.js +1 -4
- package/src/builders/application/execute-build.js +19 -2
- package/src/builders/application/execute-post-bundle.d.ts +2 -2
- package/src/builders/application/execute-post-bundle.js +58 -20
- package/src/builders/application/i18n.d.ts +2 -2
- package/src/builders/application/i18n.js +6 -16
- package/src/builders/application/index.js +8 -5
- package/src/builders/application/options.d.ts +36 -1
- package/src/builders/application/options.js +60 -3
- package/src/builders/application/schema.d.ts +15 -0
- package/src/builders/application/schema.js +11 -1
- package/src/builders/application/schema.json +5 -0
- package/src/builders/application/setup-bundling.js +12 -9
- package/src/builders/dev-server/internal.d.ts +0 -1
- package/src/builders/dev-server/internal.js +1 -3
- package/src/builders/dev-server/vite-server.d.ts +8 -2
- package/src/builders/dev-server/vite-server.js +111 -56
- package/src/builders/extract-i18n/application-extraction.js +7 -3
- package/src/tools/angular/angular-host.d.ts +2 -1
- package/src/tools/angular/angular-host.js +20 -1
- 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 +9 -1
- package/src/tools/angular/compilation/jit-compilation.js +2 -1
- package/src/tools/angular/compilation/parallel-compilation.d.ts +2 -1
- package/src/tools/angular/compilation/parallel-compilation.js +2 -10
- package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
- package/src/tools/angular/compilation/parallel-worker.js +2 -1
- package/src/tools/babel/plugins/add-code-coverage.d.ts +14 -0
- package/src/tools/babel/plugins/add-code-coverage.js +44 -0
- package/src/tools/babel/plugins/types.d.ts +20 -0
- package/src/tools/esbuild/angular/compiler-plugin.d.ts +2 -0
- package/src/tools/esbuild/angular/compiler-plugin.js +46 -4
- package/src/tools/esbuild/angular/component-stylesheets.d.ts +8 -3
- package/src/tools/esbuild/angular/component-stylesheets.js +46 -11
- package/src/tools/esbuild/angular/file-reference-tracker.d.ts +1 -1
- package/src/tools/esbuild/application-code-bundle.d.ts +2 -6
- package/src/tools/esbuild/application-code-bundle.js +208 -92
- package/src/tools/esbuild/budget-stats.js +1 -1
- package/src/tools/esbuild/bundler-context.d.ts +4 -3
- package/src/tools/esbuild/bundler-context.js +21 -13
- package/src/tools/esbuild/bundler-execution-result.d.ts +5 -2
- package/src/tools/esbuild/bundler-execution-result.js +7 -3
- package/src/tools/esbuild/cache.d.ts +6 -1
- package/src/tools/esbuild/cache.js +7 -0
- package/src/tools/esbuild/compiler-plugin-options.js +3 -1
- package/src/tools/esbuild/i18n-inliner.js +4 -4
- package/src/tools/esbuild/javascript-transformer-worker.d.ts +1 -0
- package/src/tools/esbuild/javascript-transformer-worker.js +5 -1
- package/src/tools/esbuild/javascript-transformer.d.ts +2 -2
- package/src/tools/esbuild/javascript-transformer.js +7 -12
- package/src/tools/esbuild/utils.d.ts +9 -0
- package/src/tools/esbuild/utils.js +21 -3
- package/src/tools/sass/sass-service.js +11 -13
- package/src/tools/sass/worker.d.ts +13 -32
- package/src/tools/sass/worker.js +1 -0
- package/src/tools/vite/middlewares/assets-middleware.d.ts +1 -1
- package/src/tools/vite/middlewares/assets-middleware.js +43 -4
- package/src/tools/vite/middlewares/headers-middleware.d.ts +19 -0
- package/src/tools/vite/middlewares/headers-middleware.js +34 -0
- package/src/tools/vite/middlewares/html-fallback-middleware.d.ts +1 -1
- package/src/tools/vite/middlewares/html-fallback-middleware.js +23 -7
- package/src/tools/vite/middlewares/index-html-middleware.js +1 -2
- package/src/tools/vite/middlewares/index.d.ts +2 -1
- package/src/tools/vite/middlewares/index.js +5 -2
- package/src/tools/vite/middlewares/ssr-middleware.d.ts +2 -4
- package/src/tools/vite/middlewares/ssr-middleware.js +75 -43
- package/src/tools/vite/plugins/angular-memory-plugin.d.ts +16 -0
- package/src/tools/vite/{angular-memory-plugin.js → plugins/angular-memory-plugin.js} +19 -40
- package/src/tools/vite/{i18n-locale-plugin.d.ts → plugins/i18n-locale-plugin.d.ts} +0 -4
- package/src/tools/vite/{i18n-locale-plugin.js → plugins/i18n-locale-plugin.js} +2 -3
- package/src/tools/vite/plugins/index.d.ts +12 -0
- package/src/tools/vite/plugins/index.js +21 -0
- package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +41 -0
- package/src/tools/vite/plugins/setup-middlewares-plugin.js +62 -0
- package/src/{utils/server-rendering/main-bundle-exports.js → tools/vite/plugins/ssr-transform-plugin.d.ts} +2 -2
- package/src/tools/vite/plugins/ssr-transform-plugin.js +38 -0
- package/src/tools/vite/utils.d.ts +0 -3
- package/src/tools/vite/utils.js +0 -12
- package/src/typings.d.ts +26 -0
- package/src/utils/environment-options.d.ts +2 -0
- package/src/utils/environment-options.js +5 -1
- package/src/utils/index-file/index-html-generator.js +5 -0
- package/src/utils/index-file/inline-critical-css.js +43 -33
- package/src/utils/index-file/ngcm-attribute.d.ts +15 -0
- package/src/utils/index-file/ngcm-attribute.js +37 -0
- package/src/utils/index-file/valid-self-closing-tags.js +28 -0
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/server-rendering/fetch-patch.d.ts +1 -1
- package/src/utils/server-rendering/fetch-patch.js +5 -6
- package/src/utils/server-rendering/launch-server.d.ts +14 -0
- package/src/utils/server-rendering/launch-server.js +63 -0
- package/src/utils/server-rendering/load-esm-from-memory.d.ts +18 -2
- package/src/utils/server-rendering/manifest.d.ts +50 -0
- package/src/utils/server-rendering/manifest.js +126 -0
- package/src/utils/server-rendering/models.d.ts +27 -0
- package/src/utils/server-rendering/models.js +22 -0
- package/src/utils/server-rendering/prerender.d.ts +26 -10
- package/src/utils/server-rendering/prerender.js +126 -67
- package/src/utils/server-rendering/render-worker.d.ts +9 -8
- package/src/utils/server-rendering/render-worker.js +19 -14
- package/src/utils/server-rendering/routes-extractor-worker.d.ts +6 -10
- package/src/utils/server-rendering/routes-extractor-worker.js +16 -33
- package/src/utils/server-rendering/utils.d.ts +11 -0
- package/src/utils/server-rendering/utils.js +17 -0
- package/src/utils/worker-pool.d.ts +12 -0
- package/src/utils/worker-pool.js +43 -0
- package/src/tools/vite/angular-memory-plugin.d.ts +0 -21
- package/src/utils/server-rendering/main-bundle-exports.d.ts +0 -27
- package/src/utils/server-rendering/render-page.d.ts +0 -26
- package/src/utils/server-rendering/render-page.js +0 -114
- /package/src/tools/vite/{id-prefix-plugin.d.ts → plugins/id-prefix-plugin.d.ts} +0 -0
- /package/src/tools/vite/{id-prefix-plugin.js → plugins/id-prefix-plugin.js} +0 -0
|
@@ -22,38 +22,53 @@ const MEDIA_SET_HANDLER_PATTERN = /^this\.media=["'](.*)["'];?$/;
|
|
|
22
22
|
*/
|
|
23
23
|
const CSP_MEDIA_ATTR = 'ngCspMedia';
|
|
24
24
|
/**
|
|
25
|
-
* Script
|
|
25
|
+
* Script that dynamically updates the `media` attribute of `<link>` tags based on a custom attribute (`CSP_MEDIA_ATTR`).
|
|
26
26
|
*
|
|
27
27
|
* NOTE:
|
|
28
28
|
* We do not use `document.querySelectorAll('link').forEach((s) => s.addEventListener('load', ...)`
|
|
29
|
-
* because
|
|
29
|
+
* because load events are not always triggered reliably on Chrome.
|
|
30
30
|
* See: https://github.com/angular/angular-cli/issues/26932 and https://crbug.com/1521256
|
|
31
|
+
*
|
|
32
|
+
* The script:
|
|
33
|
+
* - Ensures the event target is a `<link>` tag with the `CSP_MEDIA_ATTR` attribute.
|
|
34
|
+
* - Updates the `media` attribute with the value of `CSP_MEDIA_ATTR` and then removes the attribute.
|
|
35
|
+
* - Removes the event listener when all relevant `<link>` tags have been processed.
|
|
36
|
+
* - Uses event capturing (the `true` parameter) since load events do not bubble up the DOM.
|
|
31
37
|
*/
|
|
32
|
-
const LINK_LOAD_SCRIPT_CONTENT =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
const LINK_LOAD_SCRIPT_CONTENT = `
|
|
39
|
+
(() => {
|
|
40
|
+
const CSP_MEDIA_ATTR = '${CSP_MEDIA_ATTR}';
|
|
41
|
+
const documentElement = document.documentElement;
|
|
42
|
+
|
|
43
|
+
// Listener for load events on link tags.
|
|
44
|
+
const listener = (e) => {
|
|
45
|
+
const target = e.target;
|
|
46
|
+
if (
|
|
47
|
+
!target ||
|
|
48
|
+
target.tagName !== 'LINK' ||
|
|
49
|
+
!target.hasAttribute(CSP_MEDIA_ATTR)
|
|
50
|
+
) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
target.media = target.getAttribute(CSP_MEDIA_ATTR);
|
|
55
|
+
target.removeAttribute(CSP_MEDIA_ATTR);
|
|
56
|
+
|
|
57
|
+
if (!document.head.querySelector(\`link[\${CSP_MEDIA_ATTR}]\`)) {
|
|
58
|
+
documentElement.removeEventListener('load', listener);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
documentElement.addEventListener('load', listener, true);
|
|
63
|
+
})();
|
|
64
|
+
`.trim();
|
|
65
|
+
class CrittersBase extends critters_1.default {
|
|
66
|
+
}
|
|
67
|
+
/* eslint-enable @typescript-eslint/no-unsafe-declaration-merging */
|
|
68
|
+
class CrittersExtended extends CrittersBase {
|
|
53
69
|
optionsExtended;
|
|
54
70
|
warnings = [];
|
|
55
71
|
errors = [];
|
|
56
|
-
initialEmbedLinkedStylesheet;
|
|
57
72
|
addedCspScriptsDocuments = new WeakSet();
|
|
58
73
|
documentNonces = new WeakMap();
|
|
59
74
|
constructor(optionsExtended) {
|
|
@@ -71,17 +86,12 @@ class CrittersExtended extends critters_1.default {
|
|
|
71
86
|
reduceInlineStyles: false,
|
|
72
87
|
mergeStylesheets: false,
|
|
73
88
|
// Note: if `preload` changes to anything other than `media`, the logic in
|
|
74
|
-
// `
|
|
89
|
+
// `embedLinkedStylesheet` will have to be updated.
|
|
75
90
|
preload: 'media',
|
|
76
91
|
noscriptFallback: true,
|
|
77
92
|
inlineFonts: true,
|
|
78
93
|
});
|
|
79
94
|
this.optionsExtended = optionsExtended;
|
|
80
|
-
// We can't use inheritance to override `embedLinkedStylesheet`, because it's not declared in
|
|
81
|
-
// the `Critters` .d.ts which means that we can't call the `super` implementation. TS doesn't
|
|
82
|
-
// allow for `super` to be cast to a different type.
|
|
83
|
-
this.initialEmbedLinkedStylesheet = this.embedLinkedStylesheet;
|
|
84
|
-
this.embedLinkedStylesheet = this.embedLinkedStylesheetOverride;
|
|
85
95
|
}
|
|
86
96
|
readFile(path) {
|
|
87
97
|
const readAsset = this.optionsExtended.readAsset;
|
|
@@ -91,7 +101,7 @@ class CrittersExtended extends critters_1.default {
|
|
|
91
101
|
* Override of the Critters `embedLinkedStylesheet` method
|
|
92
102
|
* that makes it work with Angular's CSP APIs.
|
|
93
103
|
*/
|
|
94
|
-
|
|
104
|
+
async embedLinkedStylesheet(link, document) {
|
|
95
105
|
if (link.getAttribute('media') === 'print' && link.next?.name === 'noscript') {
|
|
96
106
|
// Workaround for https://github.com/GoogleChromeLabs/critters/issues/64
|
|
97
107
|
// NB: this is only needed for the webpack based builders.
|
|
@@ -102,7 +112,7 @@ class CrittersExtended extends critters_1.default {
|
|
|
102
112
|
link?.next?.remove();
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
|
-
const returnValue = await
|
|
115
|
+
const returnValue = await super.embedLinkedStylesheet(link, document);
|
|
106
116
|
const cspNonce = this.findCspNonce(document);
|
|
107
117
|
if (cspNonce) {
|
|
108
118
|
const crittersMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
|
|
@@ -126,7 +136,7 @@ class CrittersExtended extends critters_1.default {
|
|
|
126
136
|
});
|
|
127
137
|
}
|
|
128
138
|
return returnValue;
|
|
129
|
-
}
|
|
139
|
+
}
|
|
130
140
|
/**
|
|
131
141
|
* Finds the CSP nonce for a specific document.
|
|
132
142
|
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
/**
|
|
9
|
+
* Transforms the provided HTML by adding the `ngcm` attribute to the `<body>` tag.
|
|
10
|
+
* This is used in the client-side rendered (CSR) version of `index.html` to prevent hydration warnings.
|
|
11
|
+
*
|
|
12
|
+
* @param html The HTML markup to be transformed.
|
|
13
|
+
* @returns A promise that resolves to the transformed HTML string with the necessary modifications.
|
|
14
|
+
*/
|
|
15
|
+
export declare function addNgcmAttribute(html: string): Promise<string>;
|
|
@@ -0,0 +1,37 @@
|
|
|
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.addNgcmAttribute = addNgcmAttribute;
|
|
11
|
+
const html_rewriting_stream_1 = require("./html-rewriting-stream");
|
|
12
|
+
/**
|
|
13
|
+
* Defines a name of an attribute that is added to the `<body>` tag
|
|
14
|
+
* in the `index.html` file in case a given route was configured
|
|
15
|
+
* with `RenderMode.Client`. 'cm' is an abbreviation for "Client Mode".
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/angular/angular/pull/58004
|
|
18
|
+
*/
|
|
19
|
+
const CLIENT_RENDER_MODE_FLAG = 'ngcm';
|
|
20
|
+
/**
|
|
21
|
+
* Transforms the provided HTML by adding the `ngcm` attribute to the `<body>` tag.
|
|
22
|
+
* This is used in the client-side rendered (CSR) version of `index.html` to prevent hydration warnings.
|
|
23
|
+
*
|
|
24
|
+
* @param html The HTML markup to be transformed.
|
|
25
|
+
* @returns A promise that resolves to the transformed HTML string with the necessary modifications.
|
|
26
|
+
*/
|
|
27
|
+
async function addNgcmAttribute(html) {
|
|
28
|
+
const { rewriter, transformedContent } = await (0, html_rewriting_stream_1.htmlRewritingStream)(html);
|
|
29
|
+
rewriter.on('startTag', (tag) => {
|
|
30
|
+
if (tag.tagName === 'body' &&
|
|
31
|
+
!tag.attrs.some((attr) => attr.name === CLIENT_RENDER_MODE_FLAG)) {
|
|
32
|
+
tag.attrs.push({ name: CLIENT_RENDER_MODE_FLAG, value: '' });
|
|
33
|
+
}
|
|
34
|
+
rewriter.emitStartTag(tag);
|
|
35
|
+
});
|
|
36
|
+
return transformedContent();
|
|
37
|
+
}
|
|
@@ -25,8 +25,36 @@ exports.VALID_SELF_CLOSING_TAGS = new Set([
|
|
|
25
25
|
'track',
|
|
26
26
|
'wbr',
|
|
27
27
|
/** SVG tags */
|
|
28
|
+
'animate',
|
|
29
|
+
'animateMotion',
|
|
30
|
+
'animateTransform',
|
|
28
31
|
'circle',
|
|
29
32
|
'ellipse',
|
|
33
|
+
'feBlend',
|
|
34
|
+
'feColorMatrix',
|
|
35
|
+
'feComponentTransfer',
|
|
36
|
+
'feComposite',
|
|
37
|
+
'feConvolveMatrix',
|
|
38
|
+
'feDiffuseLighting',
|
|
39
|
+
'feDisplacementMap',
|
|
40
|
+
'feDistantLight',
|
|
41
|
+
'feDropShadow',
|
|
42
|
+
'feFlood',
|
|
43
|
+
'feFuncA',
|
|
44
|
+
'feFuncB',
|
|
45
|
+
'feFuncG',
|
|
46
|
+
'feFuncR',
|
|
47
|
+
'feGaussianBlur',
|
|
48
|
+
'feImage',
|
|
49
|
+
'feMerge',
|
|
50
|
+
'feMergeNode',
|
|
51
|
+
'feMorphology',
|
|
52
|
+
'feOffset',
|
|
53
|
+
'fePointLight',
|
|
54
|
+
'feSpecularLighting',
|
|
55
|
+
'feSpotLight',
|
|
56
|
+
'feTile',
|
|
57
|
+
'feTurbulence',
|
|
30
58
|
'line',
|
|
31
59
|
'path',
|
|
32
60
|
'polygon',
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.normalizeCacheOptions = normalizeCacheOptions;
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
/** Version placeholder is replaced during the build process with actual package version */
|
|
13
|
-
const VERSION = '19.0.0-next.
|
|
13
|
+
const VERSION = '19.0.0-next.10';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|
|
@@ -5,4 +5,4 @@
|
|
|
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
|
-
export declare function patchFetchToLoadInMemoryAssets(): void;
|
|
8
|
+
export declare function patchFetchToLoadInMemoryAssets(baseURL: URL): void;
|
|
@@ -17,8 +17,7 @@ const node_worker_threads_1 = require("node:worker_threads");
|
|
|
17
17
|
*/
|
|
18
18
|
const { assetFiles } = node_worker_threads_1.workerData;
|
|
19
19
|
const assetsCache = new Map();
|
|
20
|
-
|
|
21
|
-
function patchFetchToLoadInMemoryAssets() {
|
|
20
|
+
function patchFetchToLoadInMemoryAssets(baseURL) {
|
|
22
21
|
const originalFetch = globalThis.fetch;
|
|
23
22
|
const patchedFetch = async (input, init) => {
|
|
24
23
|
let url;
|
|
@@ -26,17 +25,17 @@ function patchFetchToLoadInMemoryAssets() {
|
|
|
26
25
|
url = input;
|
|
27
26
|
}
|
|
28
27
|
else if (typeof input === 'string') {
|
|
29
|
-
url = new URL(input
|
|
28
|
+
url = new URL(input);
|
|
30
29
|
}
|
|
31
30
|
else if (typeof input === 'object' && 'url' in input) {
|
|
32
|
-
url = new URL(input.url
|
|
31
|
+
url = new URL(input.url);
|
|
33
32
|
}
|
|
34
33
|
else {
|
|
35
34
|
return originalFetch(input, init);
|
|
36
35
|
}
|
|
37
|
-
const {
|
|
36
|
+
const { hostname } = url;
|
|
38
37
|
const pathname = decodeURIComponent(url.pathname);
|
|
39
|
-
if (
|
|
38
|
+
if (hostname !== baseURL.hostname || !assetFiles[pathname]) {
|
|
40
39
|
// Only handle relative requests or files that are in assets.
|
|
41
40
|
return originalFetch(input, init);
|
|
42
41
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
export declare const DEFAULT_URL: import("url").URL;
|
|
9
|
+
/**
|
|
10
|
+
* Launches a server that handles local requests.
|
|
11
|
+
*
|
|
12
|
+
* @returns A promise that resolves to the URL of the running server.
|
|
13
|
+
*/
|
|
14
|
+
export declare function launchServer(): Promise<URL>;
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DEFAULT_URL = void 0;
|
|
14
|
+
exports.launchServer = launchServer;
|
|
15
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
16
|
+
const node_http_1 = require("node:http");
|
|
17
|
+
const load_esm_1 = require("../load-esm");
|
|
18
|
+
const load_esm_from_memory_1 = require("./load-esm-from-memory");
|
|
19
|
+
const utils_1 = require("./utils");
|
|
20
|
+
exports.DEFAULT_URL = new URL('http://ng-localhost/');
|
|
21
|
+
/**
|
|
22
|
+
* Launches a server that handles local requests.
|
|
23
|
+
*
|
|
24
|
+
* @returns A promise that resolves to the URL of the running server.
|
|
25
|
+
*/
|
|
26
|
+
async function launchServer() {
|
|
27
|
+
const { default: handler } = await (0, load_esm_from_memory_1.loadEsmModuleFromMemory)('./server.mjs');
|
|
28
|
+
const { createWebRequestFromNodeRequest, writeResponseToNodeResponse } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
|
|
29
|
+
if (!(0, utils_1.isSsrNodeRequestHandler)(handler) && !(0, utils_1.isSsrRequestHandler)(handler)) {
|
|
30
|
+
return exports.DEFAULT_URL;
|
|
31
|
+
}
|
|
32
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
33
|
+
(async () => {
|
|
34
|
+
// handle request
|
|
35
|
+
if ((0, utils_1.isSsrNodeRequestHandler)(handler)) {
|
|
36
|
+
await handler(req, res, (e) => {
|
|
37
|
+
throw e;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const webRes = await handler(createWebRequestFromNodeRequest(req));
|
|
42
|
+
if (webRes) {
|
|
43
|
+
await writeResponseToNodeResponse(webRes, res);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
res.statusCode = 501;
|
|
47
|
+
res.end('Not Implemented.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})().catch((e) => {
|
|
51
|
+
res.statusCode = 500;
|
|
52
|
+
res.end('Internal Server Error.');
|
|
53
|
+
// eslint-disable-next-line no-console
|
|
54
|
+
console.error(e);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
server.unref();
|
|
58
|
+
await new Promise((resolve) => server.listen(0, 'localhost', resolve));
|
|
59
|
+
const serverAddress = server.address();
|
|
60
|
+
(0, node_assert_1.default)(serverAddress, 'Server address should be defined.');
|
|
61
|
+
(0, node_assert_1.default)(typeof serverAddress !== 'string', 'Server address should not be a string.');
|
|
62
|
+
return new URL(`http://localhost:${serverAddress.port}/`);
|
|
63
|
+
}
|
|
@@ -5,6 +5,22 @@
|
|
|
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 type { ApplicationRef, Type } from '@angular/core';
|
|
9
|
+
import type { ɵextractRoutesAndCreateRouteTree, ɵgetOrCreateAngularServerApp } from '@angular/ssr';
|
|
10
|
+
/**
|
|
11
|
+
* Represents the exports available from the main server bundle.
|
|
12
|
+
*/
|
|
13
|
+
interface MainServerBundleExports {
|
|
14
|
+
default: (() => Promise<ApplicationRef>) | Type<unknown>;
|
|
15
|
+
ɵextractRoutesAndCreateRouteTree: typeof ɵextractRoutesAndCreateRouteTree;
|
|
16
|
+
ɵgetOrCreateAngularServerApp: typeof ɵgetOrCreateAngularServerApp;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Represents the exports available from the server bundle.
|
|
20
|
+
*/
|
|
21
|
+
interface ServerBundleExports {
|
|
22
|
+
default: unknown;
|
|
23
|
+
}
|
|
9
24
|
export declare function loadEsmModuleFromMemory(path: './main.server.mjs'): Promise<MainServerBundleExports>;
|
|
10
|
-
export declare function loadEsmModuleFromMemory(path: './
|
|
25
|
+
export declare function loadEsmModuleFromMemory(path: './server.mjs'): Promise<ServerBundleExports>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
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 { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
9
|
+
import type { BuildOutputFile } from '../../tools/esbuild/bundler-context';
|
|
10
|
+
import { PrerenderedRoutesRecord } from '../../tools/esbuild/bundler-execution-result';
|
|
11
|
+
export declare const SERVER_APP_MANIFEST_FILENAME = "angular-app-manifest.mjs";
|
|
12
|
+
export declare const SERVER_APP_ENGINE_MANIFEST_FILENAME = "angular-app-engine-manifest.mjs";
|
|
13
|
+
/**
|
|
14
|
+
* Generates the server manifest for the App Engine environment.
|
|
15
|
+
*
|
|
16
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
17
|
+
* Angular application when deployed to Google App Engine. It includes the entry points
|
|
18
|
+
* for different locales and the base HREF for the application.
|
|
19
|
+
*
|
|
20
|
+
* @param i18nOptions - The internationalization options for the application build. This
|
|
21
|
+
* includes settings for inlining locales and determining the output structure.
|
|
22
|
+
* @param baseHref - The base HREF for the application. This is used to set the base URL
|
|
23
|
+
* for all relative URLs in the application.
|
|
24
|
+
* @param perenderedRoutes - A record mapping static paths to their associated data.
|
|
25
|
+
* @returns A string representing the content of the SSR server manifest for App Engine.
|
|
26
|
+
*/
|
|
27
|
+
export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], baseHref: string | undefined, perenderedRoutes?: PrerenderedRoutesRecord | undefined): string;
|
|
28
|
+
/**
|
|
29
|
+
* Generates the server manifest for the standard Node.js environment.
|
|
30
|
+
*
|
|
31
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
32
|
+
* Angular application when running in a standard Node.js environment. It includes
|
|
33
|
+
* information about the bootstrap module, whether to inline critical CSS, and any
|
|
34
|
+
* additional HTML and CSS output files.
|
|
35
|
+
*
|
|
36
|
+
* @param additionalHtmlOutputFiles - A map of additional HTML output files generated
|
|
37
|
+
* during the build process, keyed by their file paths.
|
|
38
|
+
* @param outputFiles - An array of all output files from the build process, including
|
|
39
|
+
* JavaScript and CSS files.
|
|
40
|
+
* @param inlineCriticalCss - A boolean indicating whether critical CSS should be inlined
|
|
41
|
+
* in the server-side rendered pages.
|
|
42
|
+
* @param routes - An optional array of route definitions for the application, used for
|
|
43
|
+
* server-side rendering and routing.
|
|
44
|
+
* @param locale - An optional string representing the locale or language code to be used for
|
|
45
|
+
* the application, helping with localization and rendering content specific to the locale.
|
|
46
|
+
*
|
|
47
|
+
* @returns A string representing the content of the SSR server manifest for the Node.js
|
|
48
|
+
* environment.
|
|
49
|
+
*/
|
|
50
|
+
export declare function generateAngularServerAppManifest(additionalHtmlOutputFiles: Map<string, BuildOutputFile>, outputFiles: BuildOutputFile[], inlineCriticalCss: boolean, routes: readonly unknown[] | undefined, locale: string | undefined): string;
|
|
@@ -0,0 +1,126 @@
|
|
|
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.SERVER_APP_ENGINE_MANIFEST_FILENAME = exports.SERVER_APP_MANIFEST_FILENAME = void 0;
|
|
11
|
+
exports.generateAngularServerAppEngineManifest = generateAngularServerAppEngineManifest;
|
|
12
|
+
exports.generateAngularServerAppManifest = generateAngularServerAppManifest;
|
|
13
|
+
const options_1 = require("../../builders/application/options");
|
|
14
|
+
exports.SERVER_APP_MANIFEST_FILENAME = 'angular-app-manifest.mjs';
|
|
15
|
+
exports.SERVER_APP_ENGINE_MANIFEST_FILENAME = 'angular-app-engine-manifest.mjs';
|
|
16
|
+
const MAIN_SERVER_OUTPUT_FILENAME = 'main.server.mjs';
|
|
17
|
+
/**
|
|
18
|
+
* A mapping of unsafe characters to their escaped Unicode equivalents.
|
|
19
|
+
*/
|
|
20
|
+
const UNSAFE_CHAR_MAP = {
|
|
21
|
+
'`': '\\`',
|
|
22
|
+
'$': '\\$',
|
|
23
|
+
'\\': '\\\\',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Escapes unsafe characters in a given string by replacing them with
|
|
27
|
+
* their Unicode escape sequences.
|
|
28
|
+
*
|
|
29
|
+
* @param str - The string to be escaped.
|
|
30
|
+
* @returns The escaped string where unsafe characters are replaced.
|
|
31
|
+
*/
|
|
32
|
+
function escapeUnsafeChars(str) {
|
|
33
|
+
return str.replace(/[$`\\]/g, (c) => UNSAFE_CHAR_MAP[c]);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generates the server manifest for the App Engine environment.
|
|
37
|
+
*
|
|
38
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
39
|
+
* Angular application when deployed to Google App Engine. It includes the entry points
|
|
40
|
+
* for different locales and the base HREF for the application.
|
|
41
|
+
*
|
|
42
|
+
* @param i18nOptions - The internationalization options for the application build. This
|
|
43
|
+
* includes settings for inlining locales and determining the output structure.
|
|
44
|
+
* @param baseHref - The base HREF for the application. This is used to set the base URL
|
|
45
|
+
* for all relative URLs in the application.
|
|
46
|
+
* @param perenderedRoutes - A record mapping static paths to their associated data.
|
|
47
|
+
* @returns A string representing the content of the SSR server manifest for App Engine.
|
|
48
|
+
*/
|
|
49
|
+
function generateAngularServerAppEngineManifest(i18nOptions, baseHref, perenderedRoutes = {}) {
|
|
50
|
+
const entryPointsContent = [];
|
|
51
|
+
if (i18nOptions.shouldInline) {
|
|
52
|
+
for (const locale of i18nOptions.inlineLocales) {
|
|
53
|
+
const importPath = './' + (i18nOptions.flatOutput ? '' : locale + '/') + MAIN_SERVER_OUTPUT_FILENAME;
|
|
54
|
+
let localeWithBaseHref = (0, options_1.getLocaleBaseHref)('', i18nOptions, locale) || '/';
|
|
55
|
+
// Remove leading and trailing slashes.
|
|
56
|
+
const start = localeWithBaseHref[0] === '/' ? 1 : 0;
|
|
57
|
+
const end = localeWithBaseHref[localeWithBaseHref.length - 1] === '/' ? -1 : undefined;
|
|
58
|
+
localeWithBaseHref = localeWithBaseHref.slice(start, end);
|
|
59
|
+
entryPointsContent.push(`['${localeWithBaseHref}', () => import('${importPath}')]`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
entryPointsContent.push(`['', () => import('./${MAIN_SERVER_OUTPUT_FILENAME}')]`);
|
|
64
|
+
}
|
|
65
|
+
const staticHeaders = [];
|
|
66
|
+
for (const [path, { headers }] of Object.entries(perenderedRoutes)) {
|
|
67
|
+
if (!headers) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const headersValues = [];
|
|
71
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
72
|
+
headersValues.push(`['${name}', '${encodeURIComponent(value)}']`);
|
|
73
|
+
}
|
|
74
|
+
staticHeaders.push(`['${path}', [${headersValues.join(', ')}]]`);
|
|
75
|
+
}
|
|
76
|
+
const manifestContent = `
|
|
77
|
+
export default {
|
|
78
|
+
basePath: '${baseHref ?? '/'}',
|
|
79
|
+
entryPoints: new Map([${entryPointsContent.join(', \n')}]),
|
|
80
|
+
staticPathsHeaders: new Map([${staticHeaders.join(', \n')}]),
|
|
81
|
+
};
|
|
82
|
+
`;
|
|
83
|
+
return manifestContent;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generates the server manifest for the standard Node.js environment.
|
|
87
|
+
*
|
|
88
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
89
|
+
* Angular application when running in a standard Node.js environment. It includes
|
|
90
|
+
* information about the bootstrap module, whether to inline critical CSS, and any
|
|
91
|
+
* additional HTML and CSS output files.
|
|
92
|
+
*
|
|
93
|
+
* @param additionalHtmlOutputFiles - A map of additional HTML output files generated
|
|
94
|
+
* during the build process, keyed by their file paths.
|
|
95
|
+
* @param outputFiles - An array of all output files from the build process, including
|
|
96
|
+
* JavaScript and CSS files.
|
|
97
|
+
* @param inlineCriticalCss - A boolean indicating whether critical CSS should be inlined
|
|
98
|
+
* in the server-side rendered pages.
|
|
99
|
+
* @param routes - An optional array of route definitions for the application, used for
|
|
100
|
+
* server-side rendering and routing.
|
|
101
|
+
* @param locale - An optional string representing the locale or language code to be used for
|
|
102
|
+
* the application, helping with localization and rendering content specific to the locale.
|
|
103
|
+
*
|
|
104
|
+
* @returns A string representing the content of the SSR server manifest for the Node.js
|
|
105
|
+
* environment.
|
|
106
|
+
*/
|
|
107
|
+
function generateAngularServerAppManifest(additionalHtmlOutputFiles, outputFiles, inlineCriticalCss, routes, locale) {
|
|
108
|
+
const serverAssetsContent = [];
|
|
109
|
+
for (const file of [...additionalHtmlOutputFiles.values(), ...outputFiles]) {
|
|
110
|
+
if (file.path === options_1.INDEX_HTML_SERVER ||
|
|
111
|
+
file.path === options_1.INDEX_HTML_CSR ||
|
|
112
|
+
(inlineCriticalCss && file.path.endsWith('.css'))) {
|
|
113
|
+
serverAssetsContent.push(`['${file.path}', async () => \`${escapeUnsafeChars(file.text)}\`]`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const manifestContent = `
|
|
117
|
+
export default {
|
|
118
|
+
bootstrap: () => import('./main.server.mjs').then(m => m.default),
|
|
119
|
+
inlineCriticalCss: ${inlineCriticalCss},
|
|
120
|
+
routes: ${JSON.stringify(routes, undefined, 2)},
|
|
121
|
+
assets: new Map([${serverAssetsContent.join(', \n')}]),
|
|
122
|
+
locale: ${locale !== undefined ? `'${locale}'` : undefined},
|
|
123
|
+
};
|
|
124
|
+
`;
|
|
125
|
+
return manifestContent;
|
|
126
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { RenderMode, ɵextractRoutesAndCreateRouteTree } from '@angular/ssr';
|
|
9
|
+
import { ESMInMemoryFileLoaderWorkerData } from './esm-in-memory-loader/loader-hooks';
|
|
10
|
+
type Writeable<T extends readonly unknown[]> = T extends readonly (infer U)[] ? U[] : never;
|
|
11
|
+
export interface RoutesExtractorWorkerData extends ESMInMemoryFileLoaderWorkerData {
|
|
12
|
+
assetFiles: Record</** Destination */ string, /** Source */ string>;
|
|
13
|
+
}
|
|
14
|
+
export type SerializableRouteTreeNode = ReturnType<Awaited<ReturnType<typeof ɵextractRoutesAndCreateRouteTree>>['routeTree']['toObject']>;
|
|
15
|
+
export type WritableSerializableRouteTreeNode = Writeable<SerializableRouteTreeNode>;
|
|
16
|
+
export interface RoutersExtractorWorkerResult {
|
|
17
|
+
serializedRouteTree: SerializableRouteTreeNode;
|
|
18
|
+
errors: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Local copy of `RenderMode` exported from `@angular/ssr`.
|
|
22
|
+
* This constant is needed to handle interop between CommonJS (CJS) and ES Modules (ESM) formats.
|
|
23
|
+
*
|
|
24
|
+
* It maps `RenderMode` enum values to their corresponding numeric identifiers.
|
|
25
|
+
*/
|
|
26
|
+
export declare const RouteRenderMode: Record<keyof typeof RenderMode, RenderMode>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
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.RouteRenderMode = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* Local copy of `RenderMode` exported from `@angular/ssr`.
|
|
13
|
+
* This constant is needed to handle interop between CommonJS (CJS) and ES Modules (ESM) formats.
|
|
14
|
+
*
|
|
15
|
+
* It maps `RenderMode` enum values to their corresponding numeric identifiers.
|
|
16
|
+
*/
|
|
17
|
+
exports.RouteRenderMode = {
|
|
18
|
+
AppShell: 0,
|
|
19
|
+
Server: 1,
|
|
20
|
+
Client: 2,
|
|
21
|
+
Prerender: 3,
|
|
22
|
+
};
|
|
@@ -5,19 +5,35 @@
|
|
|
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 { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
9
|
+
import { OutputMode } from '../../builders/application/schema';
|
|
8
10
|
import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
|
|
9
11
|
import { BuildOutputAsset } from '../../tools/esbuild/bundler-execution-result';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
import { SerializableRouteTreeNode } from './models';
|
|
13
|
+
type PrerenderOptions = NormalizedApplicationBuildOptions['prerenderOptions'];
|
|
14
|
+
type AppShellOptions = NormalizedApplicationBuildOptions['appShellOptions'];
|
|
15
|
+
/**
|
|
16
|
+
* Represents the output of a prerendering process.
|
|
17
|
+
*
|
|
18
|
+
* The key is the file path, and the value is an object containing the following properties:
|
|
19
|
+
*
|
|
20
|
+
* - `content`: The HTML content or output generated for the corresponding file path.
|
|
21
|
+
* - `appShellRoute`: A boolean flag indicating whether the content is an app shell.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* {
|
|
25
|
+
* '/index.html': { content: '<html>...</html>', appShell: false },
|
|
26
|
+
* '/shell/index.html': { content: '<html>...</html>', appShellRoute: true }
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
type PrerenderOutput = Record<string, {
|
|
30
|
+
content: string;
|
|
31
|
+
appShellRoute: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
export declare function prerenderPages(workspaceRoot: string, baseHref: string, appShellOptions: AppShellOptions | undefined, prerenderOptions: PrerenderOptions | undefined, outputFiles: Readonly<BuildOutputFile[]>, assets: Readonly<BuildOutputAsset[]>, outputMode: OutputMode | undefined, sourcemap?: boolean, maxThreads?: number): Promise<{
|
|
34
|
+
output: PrerenderOutput;
|
|
19
35
|
warnings: string[];
|
|
20
36
|
errors: string[];
|
|
21
|
-
|
|
37
|
+
serializableRouteTreeNode: SerializableRouteTreeNode;
|
|
22
38
|
}>;
|
|
23
39
|
export {};
|