@angular/build 19.0.0-next.1 → 19.0.0-next.11
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 +26 -22
- 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 +38 -1
- package/src/builders/application/options.js +62 -4
- package/src/builders/application/results.d.ts +5 -3
- package/src/builders/application/schema.d.ts +72 -0
- package/src/builders/application/schema.js +29 -1
- package/src/builders/application/schema.json +38 -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 +132 -58
- package/src/builders/extract-i18n/application-extraction.js +3 -3
- package/src/tools/angular/angular-host.d.ts +2 -1
- package/src/tools/angular/angular-host.js +17 -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/parallel-compilation.d.ts +2 -1
- package/src/tools/angular/compilation/parallel-compilation.js +4 -12
- package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
- package/src/tools/angular/compilation/parallel-worker.js +5 -2
- 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 +69 -10
- package/src/tools/esbuild/angular/component-stylesheets.d.ts +10 -4
- package/src/tools/esbuild/angular/component-stylesheets.js +49 -12
- package/src/tools/esbuild/angular/file-reference-tracker.d.ts +1 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +1 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.js +2 -2
- package/src/tools/esbuild/application-code-bundle.d.ts +2 -6
- package/src/tools/esbuild/application-code-bundle.js +233 -71
- 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 +24 -19
- 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 +6 -1
- package/src/tools/esbuild/global-scripts.js +1 -1
- package/src/tools/esbuild/global-styles.js +3 -0
- 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/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.d.ts +9 -0
- package/src/tools/esbuild/utils.js +33 -4
- package/src/tools/sass/sass-service.js +11 -13
- package/src/tools/sass/worker.d.ts +13 -32
- package/src/tools/sass/worker.js +20 -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/component-middleware.d.ts +9 -0
- package/src/tools/vite/middlewares/component-middleware.js +33 -0
- 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 +3 -1
- package/src/tools/vite/middlewares/index.js +7 -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 +42 -0
- package/src/tools/vite/plugins/setup-middlewares-plugin.js +63 -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 +122 -75
- 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/supported-browsers.js +1 -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
|
@@ -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 {};
|
|
@@ -6,29 +6,31 @@
|
|
|
6
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7
7
|
* found in the LICENSE file at https://angular.dev/license
|
|
8
8
|
*/
|
|
9
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
-
};
|
|
12
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
10
|
exports.prerenderPages = prerenderPages;
|
|
14
11
|
const promises_1 = require("node:fs/promises");
|
|
15
12
|
const node_path_1 = require("node:path");
|
|
16
13
|
const node_url_1 = require("node:url");
|
|
17
|
-
const
|
|
14
|
+
const schema_1 = require("../../builders/application/schema");
|
|
18
15
|
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
19
|
-
|
|
16
|
+
const error_1 = require("../error");
|
|
17
|
+
const url_1 = require("../url");
|
|
18
|
+
const worker_pool_1 = require("../worker-pool");
|
|
19
|
+
const models_1 = require("./models");
|
|
20
|
+
async function prerenderPages(workspaceRoot, baseHref, appShellOptions, prerenderOptions, outputFiles, assets, outputMode, sourcemap = false, maxThreads = 1) {
|
|
20
21
|
const outputFilesForWorker = {};
|
|
21
22
|
const serverBundlesSourceMaps = new Map();
|
|
22
23
|
const warnings = [];
|
|
23
24
|
const errors = [];
|
|
24
25
|
for (const { text, path, type } of outputFiles) {
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
if (type !== bundler_context_1.BuildOutputFileType.ServerApplication && type !== bundler_context_1.BuildOutputFileType.ServerRoot) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Contains the server runnable application code
|
|
30
|
+
if ((0, node_path_1.extname)(path) === '.map') {
|
|
27
31
|
serverBundlesSourceMaps.set(path.slice(0, -4), text);
|
|
28
32
|
}
|
|
29
|
-
else
|
|
30
|
-
(type === bundler_context_1.BuildOutputFileType.Browser && fileExt === '.css') // Global styles for critical CSS inlining.
|
|
31
|
-
) {
|
|
33
|
+
else {
|
|
32
34
|
outputFilesForWorker[path] = text;
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -49,40 +51,58 @@ async function prerenderPages(workspaceRoot, appShellOptions = {}, prerenderOpti
|
|
|
49
51
|
assetsReversed[addLeadingSlash(destination.replace(/\\/g, node_path_1.posix.sep))] = source;
|
|
50
52
|
}
|
|
51
53
|
// Get routes to prerender
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const { errors: extractionErrors, serializedRouteTree: serializableRouteTreeNode } = await getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, assetsReversed, appShellOptions, prerenderOptions, sourcemap, outputMode).catch((err) => {
|
|
55
|
+
return {
|
|
56
|
+
errors: [
|
|
57
|
+
`An error occurred while extracting routes.\n\n${err.stack ?? err.message ?? err}`,
|
|
58
|
+
],
|
|
59
|
+
serializedRouteTree: [],
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
errors.push(...extractionErrors);
|
|
63
|
+
const serializableRouteTreeNodeForPrerender = [];
|
|
64
|
+
for (const metadata of serializableRouteTreeNode) {
|
|
65
|
+
if (outputMode !== schema_1.OutputMode.Static && metadata.redirectTo) {
|
|
66
|
+
// Skip redirects if output mode is not static.
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (metadata.route.includes('*')) {
|
|
70
|
+
// Skip catch all routes from prerender.
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
switch (metadata.renderMode) {
|
|
74
|
+
case undefined: /* Legacy building mode */
|
|
75
|
+
case models_1.RouteRenderMode.Prerender:
|
|
76
|
+
case models_1.RouteRenderMode.AppShell:
|
|
77
|
+
serializableRouteTreeNodeForPrerender.push(metadata);
|
|
78
|
+
break;
|
|
79
|
+
case models_1.RouteRenderMode.Server:
|
|
80
|
+
if (outputMode === schema_1.OutputMode.Static) {
|
|
81
|
+
errors.push(`Route '${metadata.route}' is configured with server render mode, but the build 'outputMode' is set to 'static'.`);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
58
85
|
}
|
|
59
|
-
if (
|
|
86
|
+
if (!serializableRouteTreeNodeForPrerender.length || errors.length > 0) {
|
|
60
87
|
return {
|
|
61
88
|
errors,
|
|
62
89
|
warnings,
|
|
63
90
|
output: {},
|
|
64
|
-
|
|
91
|
+
serializableRouteTreeNode,
|
|
65
92
|
};
|
|
66
93
|
}
|
|
67
94
|
// Render routes
|
|
68
|
-
const {
|
|
95
|
+
const { errors: renderingErrors, output } = await renderPages(baseHref, sourcemap, serializableRouteTreeNodeForPrerender, maxThreads, workspaceRoot, outputFilesForWorker, assetsReversed, appShellOptions, outputMode);
|
|
69
96
|
errors.push(...renderingErrors);
|
|
70
|
-
warnings.push(...renderingWarnings);
|
|
71
97
|
return {
|
|
72
98
|
errors,
|
|
73
99
|
warnings,
|
|
74
100
|
output,
|
|
75
|
-
|
|
101
|
+
serializableRouteTreeNode,
|
|
76
102
|
};
|
|
77
103
|
}
|
|
78
|
-
|
|
79
|
-
add(value) {
|
|
80
|
-
return super.add(addLeadingSlash(value));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async function renderPages(sourcemap, allRoutes, maxThreads, workspaceRoot, outputFilesForWorker, assetFilesForWorker, inlineCriticalCss, document, appShellOptions) {
|
|
104
|
+
async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxThreads, workspaceRoot, outputFilesForWorker, assetFilesForWorker, appShellOptions, outputMode) {
|
|
84
105
|
const output = {};
|
|
85
|
-
const warnings = [];
|
|
86
106
|
const errors = [];
|
|
87
107
|
const workerExecArgv = [
|
|
88
108
|
'--import',
|
|
@@ -92,43 +112,42 @@ async function renderPages(sourcemap, allRoutes, maxThreads, workspaceRoot, outp
|
|
|
92
112
|
if (sourcemap) {
|
|
93
113
|
workerExecArgv.push('--enable-source-maps');
|
|
94
114
|
}
|
|
95
|
-
const renderWorker = new
|
|
115
|
+
const renderWorker = new worker_pool_1.WorkerPool({
|
|
96
116
|
filename: require.resolve('./render-worker'),
|
|
97
|
-
maxThreads: Math.min(
|
|
117
|
+
maxThreads: Math.min(serializableRouteTreeNode.length, maxThreads),
|
|
98
118
|
workerData: {
|
|
99
119
|
workspaceRoot,
|
|
100
120
|
outputFiles: outputFilesForWorker,
|
|
101
121
|
assetFiles: assetFilesForWorker,
|
|
102
|
-
|
|
103
|
-
|
|
122
|
+
outputMode,
|
|
123
|
+
hasSsrEntry: !!outputFilesForWorker['server.mjs'],
|
|
104
124
|
},
|
|
105
125
|
execArgv: workerExecArgv,
|
|
106
|
-
recordTiming: false,
|
|
107
126
|
});
|
|
108
127
|
try {
|
|
109
128
|
const renderingPromises = [];
|
|
110
|
-
const appShellRoute = appShellOptions
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
129
|
+
const appShellRoute = appShellOptions && addLeadingSlash(appShellOptions.route);
|
|
130
|
+
const baseHrefWithLeadingSlash = addLeadingSlash(baseHref);
|
|
131
|
+
for (const { route, redirectTo, renderMode } of serializableRouteTreeNode) {
|
|
132
|
+
// Remove base href from file output path.
|
|
133
|
+
const routeWithoutBaseHref = addLeadingSlash(route.slice(baseHrefWithLeadingSlash.length - 1));
|
|
134
|
+
const outPath = node_path_1.posix.join(removeLeadingSlash(routeWithoutBaseHref), 'index.html');
|
|
135
|
+
if (typeof redirectTo === 'string') {
|
|
136
|
+
output[outPath] = { content: generateRedirectStaticPage(redirectTo), appShellRoute: false };
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const isAppShellRoute = renderMode === models_1.RouteRenderMode.AppShell ||
|
|
140
|
+
// Legacy handling
|
|
141
|
+
(renderMode === undefined && appShellRoute === routeWithoutBaseHref);
|
|
142
|
+
const render = renderWorker.run({ url: route, isAppShellRoute });
|
|
115
143
|
const renderResult = render
|
|
116
|
-
.then((
|
|
117
|
-
if (content !==
|
|
118
|
-
|
|
119
|
-
? 'index.html'
|
|
120
|
-
: node_path_1.posix.join(removeLeadingSlash(route), 'index.html');
|
|
121
|
-
output[outPath] = content;
|
|
122
|
-
}
|
|
123
|
-
if (warnings) {
|
|
124
|
-
warnings.push(...warnings);
|
|
125
|
-
}
|
|
126
|
-
if (errors) {
|
|
127
|
-
errors.push(...errors);
|
|
144
|
+
.then((content) => {
|
|
145
|
+
if (content !== null) {
|
|
146
|
+
output[outPath] = { content, appShellRoute: isAppShellRoute };
|
|
128
147
|
}
|
|
129
148
|
})
|
|
130
149
|
.catch((err) => {
|
|
131
|
-
errors.push(`An error occurred while prerendering route '${route}'.\n\n${err.stack}`);
|
|
150
|
+
errors.push(`An error occurred while prerendering route '${route}'.\n\n${err.stack ?? err.message ?? err.code ?? err}`);
|
|
132
151
|
void renderWorker.destroy();
|
|
133
152
|
});
|
|
134
153
|
renderingPromises.push(renderResult);
|
|
@@ -140,25 +159,27 @@ async function renderPages(sourcemap, allRoutes, maxThreads, workspaceRoot, outp
|
|
|
140
159
|
}
|
|
141
160
|
return {
|
|
142
161
|
errors,
|
|
143
|
-
warnings,
|
|
144
162
|
output,
|
|
145
163
|
};
|
|
146
164
|
}
|
|
147
|
-
async function getAllRoutes(workspaceRoot, outputFilesForWorker, assetFilesForWorker,
|
|
148
|
-
const { routesFile, discoverRoutes } = prerenderOptions;
|
|
149
|
-
const routes =
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
165
|
+
async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, assetFilesForWorker, appShellOptions, prerenderOptions, sourcemap, outputMode) {
|
|
166
|
+
const { routesFile, discoverRoutes } = prerenderOptions ?? {};
|
|
167
|
+
const routes = [];
|
|
168
|
+
if (appShellOptions) {
|
|
169
|
+
routes.push({
|
|
170
|
+
route: (0, url_1.urlJoin)(baseHref, appShellOptions.route),
|
|
171
|
+
});
|
|
153
172
|
}
|
|
154
173
|
if (routesFile) {
|
|
155
174
|
const routesFromFile = (await (0, promises_1.readFile)(routesFile, 'utf8')).split(/\r?\n/);
|
|
156
175
|
for (const route of routesFromFile) {
|
|
157
|
-
routes.
|
|
176
|
+
routes.push({
|
|
177
|
+
route: (0, url_1.urlJoin)(baseHref, route.trim()),
|
|
178
|
+
});
|
|
158
179
|
}
|
|
159
180
|
}
|
|
160
181
|
if (!discoverRoutes) {
|
|
161
|
-
return { routes };
|
|
182
|
+
return { errors: [], serializedRouteTree: routes };
|
|
162
183
|
}
|
|
163
184
|
const workerExecArgv = [
|
|
164
185
|
'--import',
|
|
@@ -168,32 +189,34 @@ async function getAllRoutes(workspaceRoot, outputFilesForWorker, assetFilesForWo
|
|
|
168
189
|
if (sourcemap) {
|
|
169
190
|
workerExecArgv.push('--enable-source-maps');
|
|
170
191
|
}
|
|
171
|
-
const renderWorker = new
|
|
192
|
+
const renderWorker = new worker_pool_1.WorkerPool({
|
|
172
193
|
filename: require.resolve('./routes-extractor-worker'),
|
|
173
194
|
maxThreads: 1,
|
|
174
195
|
workerData: {
|
|
175
196
|
workspaceRoot,
|
|
176
197
|
outputFiles: outputFilesForWorker,
|
|
177
198
|
assetFiles: assetFilesForWorker,
|
|
178
|
-
|
|
179
|
-
|
|
199
|
+
outputMode,
|
|
200
|
+
hasSsrEntry: !!outputFilesForWorker['server.mjs'],
|
|
180
201
|
},
|
|
181
202
|
execArgv: workerExecArgv,
|
|
182
|
-
recordTiming: false,
|
|
183
203
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
204
|
+
try {
|
|
205
|
+
const { serializedRouteTree, errors } = await renderWorker.run({});
|
|
206
|
+
return { errors, serializedRouteTree: [...routes, ...serializedRouteTree] };
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
(0, error_1.assertIsError)(err);
|
|
210
|
+
return {
|
|
211
|
+
errors: [
|
|
212
|
+
`An error occurred while extracting routes.\n\n${err.stack ?? err.message ?? err.code ?? err}`,
|
|
213
|
+
],
|
|
214
|
+
serializedRouteTree: [],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
191
218
|
void renderWorker.destroy();
|
|
192
|
-
});
|
|
193
|
-
for (const route of extractedRoutes) {
|
|
194
|
-
routes.add(route);
|
|
195
219
|
}
|
|
196
|
-
return { routes, warnings, errors };
|
|
197
220
|
}
|
|
198
221
|
function addLeadingSlash(value) {
|
|
199
222
|
return value.charAt(0) === '/' ? value : '/' + value;
|
|
@@ -201,3 +224,27 @@ function addLeadingSlash(value) {
|
|
|
201
224
|
function removeLeadingSlash(value) {
|
|
202
225
|
return value.charAt(0) === '/' ? value.slice(1) : value;
|
|
203
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Generates a static HTML page with a meta refresh tag to redirect the user to a specified URL.
|
|
229
|
+
*
|
|
230
|
+
* This function creates a simple HTML page that performs a redirect using a meta tag.
|
|
231
|
+
* It includes a fallback link in case the meta-refresh doesn't work.
|
|
232
|
+
*
|
|
233
|
+
* @param url - The URL to which the page should redirect.
|
|
234
|
+
* @returns The HTML content of the static redirect page.
|
|
235
|
+
*/
|
|
236
|
+
function generateRedirectStaticPage(url) {
|
|
237
|
+
return `
|
|
238
|
+
<!DOCTYPE html>
|
|
239
|
+
<html>
|
|
240
|
+
<head>
|
|
241
|
+
<meta charset="utf-8">
|
|
242
|
+
<title>Redirecting</title>
|
|
243
|
+
<meta http-equiv="refresh" content="0; url=${url}">
|
|
244
|
+
</head>
|
|
245
|
+
<body>
|
|
246
|
+
<pre>Redirecting to <a href="${url}">${url}</a></pre>
|
|
247
|
+
</body>
|
|
248
|
+
</html>
|
|
249
|
+
`.trim();
|
|
250
|
+
}
|
|
@@ -5,18 +5,19 @@
|
|
|
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 type { OutputMode } from '../../builders/application/schema';
|
|
8
9
|
import type { ESMInMemoryFileLoaderWorkerData } from './esm-in-memory-loader/loader-hooks';
|
|
9
|
-
import { RenderResult, ServerContext } from './render-page';
|
|
10
10
|
export interface RenderWorkerData extends ESMInMemoryFileLoaderWorkerData {
|
|
11
|
-
document: string;
|
|
12
|
-
inlineCriticalCss?: boolean;
|
|
13
11
|
assetFiles: Record</** Destination */ string, /** Source */ string>;
|
|
12
|
+
outputMode: OutputMode | undefined;
|
|
13
|
+
hasSsrEntry: boolean;
|
|
14
14
|
}
|
|
15
15
|
export interface RenderOptions {
|
|
16
|
-
|
|
17
|
-
serverContext: ServerContext;
|
|
16
|
+
url: string;
|
|
18
17
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Renders each route in routes and writes them to <outputPath>/<route>/index.html.
|
|
20
|
+
*/
|
|
21
|
+
declare function renderPage({ url }: RenderOptions): Promise<string | null>;
|
|
22
|
+
declare const _default: Promise<typeof renderPage>;
|
|
22
23
|
export default _default;
|
|
@@ -7,24 +7,29 @@
|
|
|
7
7
|
* found in the LICENSE file at https://angular.dev/license
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const
|
|
10
|
+
const worker_threads_1 = require("worker_threads");
|
|
11
11
|
const fetch_patch_1 = require("./fetch-patch");
|
|
12
|
-
const
|
|
12
|
+
const launch_server_1 = require("./launch-server");
|
|
13
|
+
const load_esm_from_memory_1 = require("./load-esm-from-memory");
|
|
13
14
|
/**
|
|
14
15
|
* This is passed as workerData when setting up the worker via the `piscina` package.
|
|
15
16
|
*/
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const { outputMode, hasSsrEntry } = worker_threads_1.workerData;
|
|
18
|
+
let serverURL = launch_server_1.DEFAULT_URL;
|
|
19
|
+
/**
|
|
20
|
+
* Renders each route in routes and writes them to <outputPath>/<route>/index.html.
|
|
21
|
+
*/
|
|
22
|
+
async function renderPage({ url }) {
|
|
23
|
+
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = await (0, load_esm_from_memory_1.loadEsmModuleFromMemory)('./main.server.mjs');
|
|
24
|
+
const angularServerApp = getOrCreateAngularServerApp();
|
|
25
|
+
const response = await angularServerApp.renderStatic(new URL(url, serverURL), AbortSignal.timeout(30_000));
|
|
26
|
+
return response ? response.text() : null;
|
|
25
27
|
}
|
|
26
|
-
function initialize() {
|
|
27
|
-
(
|
|
28
|
-
|
|
28
|
+
async function initialize() {
|
|
29
|
+
if (outputMode !== undefined && hasSsrEntry) {
|
|
30
|
+
serverURL = await (0, launch_server_1.launchServer)();
|
|
31
|
+
}
|
|
32
|
+
(0, fetch_patch_1.patchFetchToLoadInMemoryAssets)(serverURL);
|
|
33
|
+
return renderPage;
|
|
29
34
|
}
|
|
30
35
|
exports.default = initialize();
|
|
@@ -5,17 +5,13 @@
|
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
export interface RoutersExtractorWorkerResult {
|
|
15
|
-
routes: string[];
|
|
16
|
-
warnings?: string[];
|
|
8
|
+
import { OutputMode } from '../../builders/application/schema';
|
|
9
|
+
import { ESMInMemoryFileLoaderWorkerData } from './esm-in-memory-loader/loader-hooks';
|
|
10
|
+
import { RoutersExtractorWorkerResult } from './models';
|
|
11
|
+
export interface ExtractRoutesWorkerData extends ESMInMemoryFileLoaderWorkerData {
|
|
12
|
+
outputMode: OutputMode | undefined;
|
|
17
13
|
}
|
|
18
14
|
/** Renders an application based on a provided options. */
|
|
19
15
|
declare function extractRoutes(): Promise<RoutersExtractorWorkerResult>;
|
|
20
|
-
declare const _default: typeof extractRoutes
|
|
16
|
+
declare const _default: Promise<typeof extractRoutes>;
|
|
21
17
|
export default _default;
|