@angular/build 19.0.0-rc.0 → 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 +6 -6
- package/src/builders/application/build-action.js +13 -1
- package/src/builders/application/execute-build.js +38 -31
- package/src/builders/application/execute-post-bundle.js +19 -4
- package/src/builders/application/options.d.ts +10 -1
- package/src/builders/application/options.js +9 -0
- package/src/builders/application/setup-bundling.d.ts +4 -1
- package/src/builders/application/setup-bundling.js +18 -11
- 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 +2 -1
- package/src/builders/dev-server/vite-server.js +94 -61
- package/src/tools/angular/angular-host.js +13 -2
- package/src/tools/esbuild/angular/compiler-plugin.d.ts +1 -0
- package/src/tools/esbuild/angular/compiler-plugin.js +5 -0
- package/src/tools/esbuild/angular/component-stylesheets.d.ts +1 -0
- package/src/tools/esbuild/angular/component-stylesheets.js +3 -0
- 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 +5 -4
- package/src/tools/esbuild/application-code-bundle.js +245 -239
- package/src/tools/esbuild/bundler-execution-result.d.ts +10 -2
- package/src/tools/esbuild/bundler-execution-result.js +12 -9
- package/src/tools/esbuild/compiler-plugin-options.d.ts +2 -1
- package/src/tools/esbuild/compiler-plugin-options.js +3 -2
- package/src/tools/esbuild/javascript-transformer.js +2 -1
- package/src/tools/esbuild/server-bundle-metadata-plugin.d.ts +1 -1
- package/src/tools/esbuild/server-bundle-metadata-plugin.js +1 -1
- package/src/tools/vite/middlewares/assets-middleware.d.ts +6 -1
- package/src/tools/vite/middlewares/assets-middleware.js +27 -23
- package/src/tools/vite/middlewares/component-middleware.js +1 -1
- package/src/tools/vite/middlewares/index.d.ts +1 -1
- package/src/tools/vite/middlewares/ssr-middleware.js +5 -2
- 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 +2 -1
- package/src/tools/vite/plugins/setup-middlewares-plugin.js +11 -3
- package/src/utils/environment-options.d.ts +1 -0
- package/src/utils/environment-options.js +3 -1
- 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/manifest.d.ts +9 -8
- package/src/utils/server-rendering/manifest.js +17 -23
- package/src/utils/server-rendering/prerender.js +25 -16
- package/src/utils/server-rendering/render-worker.js +4 -2
|
@@ -8,6 +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, sourceFileCache?:
|
|
13
|
+
export declare function createCompilerPluginOptions(options: NormalizedApplicationBuildOptions, sourceFileCache: SourceFileCache, loadResultCache?: LoadResultCache, templateUpdates?: Map<string, string>): CreateCompilerPluginParameters[0];
|
|
13
14
|
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.createCompilerPluginOptions = createCompilerPluginOptions;
|
|
11
|
-
function createCompilerPluginOptions(options, sourceFileCache) {
|
|
11
|
+
function createCompilerPluginOptions(options, sourceFileCache, loadResultCache, templateUpdates) {
|
|
12
12
|
const { sourcemapOptions, tsconfig, fileReplacements, advancedOptimizations, jit, externalRuntimeStyles, instrumentForCoverage, } = options;
|
|
13
13
|
const incremental = !!options.watch;
|
|
14
14
|
return {
|
|
@@ -19,9 +19,10 @@ function createCompilerPluginOptions(options, sourceFileCache) {
|
|
|
19
19
|
advancedOptimizations,
|
|
20
20
|
fileReplacements,
|
|
21
21
|
sourceFileCache,
|
|
22
|
-
loadResultCache
|
|
22
|
+
loadResultCache,
|
|
23
23
|
incremental,
|
|
24
24
|
externalRuntimeStyles,
|
|
25
25
|
instrumentForCoverage,
|
|
26
|
+
templateUpdates,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
@@ -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.
|
|
@@ -42,7 +43,7 @@ class JavaScriptTransformer {
|
|
|
42
43
|
filename: require.resolve('./javascript-transformer-worker'),
|
|
43
44
|
maxThreads: this.maxThreads,
|
|
44
45
|
// Prevent passing `--import` (loader-hooks) from parent to child worker.
|
|
45
|
-
execArgv:
|
|
46
|
+
execArgv: process.execArgv.filter((v) => v !== utils_1.IMPORT_EXEC_ARGV),
|
|
46
47
|
});
|
|
47
48
|
return this.#workerPool;
|
|
48
49
|
}
|
|
@@ -13,7 +13,7 @@ import type { Plugin } from 'esbuild';
|
|
|
13
13
|
* @param options Optional configuration object.
|
|
14
14
|
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
15
15
|
*
|
|
16
|
-
* @
|
|
16
|
+
* @remarks We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
17
17
|
* is used for non-SSR-related code too (e.g., global scripts).
|
|
18
18
|
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
19
19
|
*/
|
|
@@ -15,7 +15,7 @@ exports.createServerBundleMetadata = createServerBundleMetadata;
|
|
|
15
15
|
* @param options Optional configuration object.
|
|
16
16
|
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
17
17
|
*
|
|
18
|
-
* @
|
|
18
|
+
* @remarks We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
19
19
|
* is used for non-SSR-related code too (e.g., global scripts).
|
|
20
20
|
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
21
21
|
*/
|
|
@@ -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;
|
|
@@ -10,9 +10,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.createAngularAssetsMiddleware = createAngularAssetsMiddleware;
|
|
11
11
|
const mrmime_1 = require("mrmime");
|
|
12
12
|
const node_path_1 = require("node:path");
|
|
13
|
-
const load_esm_1 = require("../../../utils/load-esm");
|
|
14
13
|
const utils_1 = require("../utils");
|
|
15
|
-
function createAngularAssetsMiddleware(server, assets, outputFiles,
|
|
14
|
+
function createAngularAssetsMiddleware(server, assets, outputFiles, componentStyles, encapsulateStyle) {
|
|
16
15
|
return function angularAssetsMiddleware(req, res, next) {
|
|
17
16
|
if (req.url === undefined || res.writableEnded) {
|
|
18
17
|
return;
|
|
@@ -59,18 +58,25 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, usedComponen
|
|
|
59
58
|
if (extension !== '.js' && extension !== '.html') {
|
|
60
59
|
const outputFile = outputFiles.get(pathname);
|
|
61
60
|
if (outputFile?.servable) {
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
let data = outputFile.contents;
|
|
62
|
+
const componentStyle = componentStyles.get(pathname);
|
|
63
|
+
if (componentStyle) {
|
|
64
64
|
// Inject component ID for view encapsulation if requested
|
|
65
|
-
const
|
|
65
|
+
const searchParams = new URL(req.url, 'http://localhost').searchParams;
|
|
66
|
+
const componentId = searchParams.get('ngcomp');
|
|
66
67
|
if (componentId !== null) {
|
|
68
|
+
// Track if the component uses ShadowDOM encapsulation (3 = ViewEncapsulation.ShadowDom)
|
|
69
|
+
// Shadow DOM components currently require a full reload.
|
|
70
|
+
// Vite's CSS hot replacement does not support shadow root searching.
|
|
71
|
+
if (searchParams.get('e') === '3') {
|
|
72
|
+
componentStyle.reload = true;
|
|
73
|
+
}
|
|
67
74
|
// Record the component style usage for HMR updates
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
usedComponentStyles.set(pathname, new Set([componentId]));
|
|
75
|
+
if (componentStyle.used === undefined) {
|
|
76
|
+
componentStyle.used = new Set([componentId]);
|
|
71
77
|
}
|
|
72
78
|
else {
|
|
73
|
-
|
|
79
|
+
componentStyle.used.add(componentId);
|
|
74
80
|
}
|
|
75
81
|
// Report if there are no changes to avoid reprocessing
|
|
76
82
|
const etag = `W/"${outputFile.contents.byteLength}-${outputFile.hash}-${componentId}"`;
|
|
@@ -82,23 +88,21 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, usedComponen
|
|
|
82
88
|
// Shim the stylesheet if a component ID is provided
|
|
83
89
|
if (componentId.length > 0) {
|
|
84
90
|
// Validate component ID
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
.then((compilerModule) => {
|
|
88
|
-
const encapsulatedData = compilerModule.encapsulateStyle(new TextDecoder().decode(data), componentId);
|
|
89
|
-
res.setHeader('Content-Type', 'text/css');
|
|
90
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
91
|
-
res.setHeader('ETag', etag);
|
|
92
|
-
res.end(encapsulatedData);
|
|
93
|
-
})
|
|
94
|
-
.catch((e) => next(e));
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
91
|
+
if (!/^[_.\-\p{Letter}\d]+-c\d+$/u.test(componentId)) {
|
|
92
|
+
const message = 'Invalid component stylesheet ID request: ' + componentId;
|
|
98
93
|
// eslint-disable-next-line no-console
|
|
99
|
-
console.error(
|
|
94
|
+
console.error(message);
|
|
95
|
+
res.statusCode = 400;
|
|
96
|
+
res.end(message);
|
|
97
|
+
return;
|
|
100
98
|
}
|
|
99
|
+
data = encapsulateStyle(data, componentId);
|
|
101
100
|
}
|
|
101
|
+
res.setHeader('Content-Type', 'text/css');
|
|
102
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
103
|
+
res.setHeader('ETag', etag);
|
|
104
|
+
res.end(data);
|
|
105
|
+
return;
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
// Avoid resending the content if it has not changed since last request
|
|
@@ -25,7 +25,7 @@ function createAngularComponentMiddleware(templateUpdates) {
|
|
|
25
25
|
res.end();
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
const updateCode = templateUpdates.get(componentId) ?? '';
|
|
28
|
+
const updateCode = templateUpdates.get(encodeURIComponent(componentId)) ?? '';
|
|
29
29
|
res.setHeader('Content-Type', 'text/javascript');
|
|
30
30
|
res.setHeader('Cache-Control', 'no-cache');
|
|
31
31
|
res.end(updateCode);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
|
-
export { createAngularAssetsMiddleware } from './assets-middleware';
|
|
8
|
+
export { type ComponentStyleRecord, createAngularAssetsMiddleware } from './assets-middleware';
|
|
9
9
|
export { angularHtmlFallbackMiddleware } from './html-fallback-middleware';
|
|
10
10
|
export { createAngularIndexHtmlMiddleware } from './index-html-middleware';
|
|
11
11
|
export { createAngularSsrExternalMiddleware, createAngularSsrInternalMiddleware, } from './ssr-middleware';
|
|
@@ -23,7 +23,9 @@ function createAngularSsrInternalMiddleware(server, indexHtmlTransformer) {
|
|
|
23
23
|
await (0, load_esm_1.loadEsmModule)('@angular/compiler');
|
|
24
24
|
const { writeResponseToNodeResponse, createWebRequestFromNodeRequest } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
|
|
25
25
|
const { ɵgetOrCreateAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
|
|
26
|
-
const angularServerApp = ɵgetOrCreateAngularServerApp(
|
|
26
|
+
const angularServerApp = ɵgetOrCreateAngularServerApp({
|
|
27
|
+
allowStaticRouteRender: true,
|
|
28
|
+
});
|
|
27
29
|
// Only Add the transform hook only if it's a different instance.
|
|
28
30
|
if (cachedAngularServerApp !== angularServerApp) {
|
|
29
31
|
angularServerApp.hooks.on('html:transform:pre', async ({ html, url }) => {
|
|
@@ -35,7 +37,7 @@ function createAngularSsrInternalMiddleware(server, indexHtmlTransformer) {
|
|
|
35
37
|
const webReq = new Request(createWebRequestFromNodeRequest(req), {
|
|
36
38
|
signal: AbortSignal.timeout(30_000),
|
|
37
39
|
});
|
|
38
|
-
const webRes = await angularServerApp.
|
|
40
|
+
const webRes = await angularServerApp.handle(webReq);
|
|
39
41
|
if (!webRes) {
|
|
40
42
|
return next();
|
|
41
43
|
}
|
|
@@ -66,6 +68,7 @@ async function createAngularSsrExternalMiddleware(server, indexHtmlTransformer)
|
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
70
|
if (cachedAngularAppEngine !== AngularAppEngine) {
|
|
71
|
+
AngularAppEngine.ɵallowStaticRouteRender = true;
|
|
69
72
|
AngularAppEngine.ɵhooks.on('html:transform:pre', async ({ html, url }) => {
|
|
70
73
|
const processedHtml = await server.transformIndexHtml(url.pathname, html);
|
|
71
74
|
return indexHtmlTransformer?.(processedHtml) ?? processedHtml;
|
|
@@ -11,6 +11,7 @@ interface AngularMemoryPluginOptions {
|
|
|
11
11
|
virtualProjectRoot: string;
|
|
12
12
|
outputFiles: AngularMemoryOutputFiles;
|
|
13
13
|
external?: string[];
|
|
14
|
+
skipViteClient?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export declare function createAngularMemoryPlugin(options: AngularMemoryPluginOptions): Promise<Plugin>;
|
|
16
17
|
export {};
|
|
@@ -18,8 +18,6 @@ const load_esm_1 = require("../../../utils/load-esm");
|
|
|
18
18
|
async function createAngularMemoryPlugin(options) {
|
|
19
19
|
const { virtualProjectRoot, outputFiles, external } = options;
|
|
20
20
|
const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
|
|
21
|
-
// See: https://github.com/vitejs/vite/blob/a34a73a3ad8feeacc98632c0f4c643b6820bbfda/packages/vite/src/node/server/pluginContainer.ts#L331-L334
|
|
22
|
-
const defaultImporter = (0, node_path_1.join)(virtualProjectRoot, 'index.html');
|
|
23
21
|
return {
|
|
24
22
|
name: 'vite:angular-memory',
|
|
25
23
|
// Ensures plugin hooks run before built-in Vite hooks
|
|
@@ -32,17 +30,10 @@ async function createAngularMemoryPlugin(options) {
|
|
|
32
30
|
return source;
|
|
33
31
|
}
|
|
34
32
|
if (importer) {
|
|
35
|
-
let normalizedSource;
|
|
36
33
|
if (source[0] === '.' && normalizePath(importer).startsWith(virtualProjectRoot)) {
|
|
37
34
|
// Remove query if present
|
|
38
35
|
const [importerFile] = importer.split('?', 1);
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
else if (source[0] === '/' && importer === defaultImporter) {
|
|
42
|
-
normalizedSource = (0, node_path_1.basename)(source);
|
|
43
|
-
}
|
|
44
|
-
if (normalizedSource) {
|
|
45
|
-
source = '/' + normalizePath(normalizedSource);
|
|
36
|
+
source = '/' + (0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.relative)(virtualProjectRoot, importerFile)), source);
|
|
46
37
|
}
|
|
47
38
|
}
|
|
48
39
|
const [file] = source.split('?', 1);
|
|
@@ -55,9 +46,10 @@ async function createAngularMemoryPlugin(options) {
|
|
|
55
46
|
const relativeFile = '/' + normalizePath((0, node_path_1.relative)(virtualProjectRoot, file));
|
|
56
47
|
const codeContents = outputFiles.get(relativeFile)?.contents;
|
|
57
48
|
if (codeContents === undefined) {
|
|
58
|
-
|
|
59
|
-
? loadViteClientCode(file)
|
|
60
|
-
|
|
49
|
+
if (relativeFile.endsWith('/node_modules/vite/dist/client/client.mjs')) {
|
|
50
|
+
return options.skipViteClient ? '' : loadViteClientCode(file);
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
61
53
|
}
|
|
62
54
|
const code = Buffer.from(codeContents).toString('utf-8');
|
|
63
55
|
const mapContents = outputFiles.get(relativeFile + '.map')?.contents;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import type { Connect, Plugin } from 'vite';
|
|
9
|
+
import { ComponentStyleRecord } from '../middlewares';
|
|
9
10
|
import { AngularMemoryOutputFiles } from '../utils';
|
|
10
11
|
export declare enum ServerSsrMode {
|
|
11
12
|
/**
|
|
@@ -34,7 +35,7 @@ interface AngularSetupMiddlewaresPluginOptions {
|
|
|
34
35
|
assets: Map<string, string>;
|
|
35
36
|
extensionMiddleware?: Connect.NextHandleFunction[];
|
|
36
37
|
indexHtmlTransformer?: (content: string) => Promise<string>;
|
|
37
|
-
|
|
38
|
+
componentStyles: Map<string, ComponentStyleRecord>;
|
|
38
39
|
templateUpdates: Map<string, string>;
|
|
39
40
|
ssrMode: ServerSsrMode;
|
|
40
41
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.ServerSsrMode = void 0;
|
|
11
11
|
exports.createAngularSetupMiddlewaresPlugin = createAngularSetupMiddlewaresPlugin;
|
|
12
|
+
const load_esm_1 = require("../../../utils/load-esm");
|
|
12
13
|
const middlewares_1 = require("../middlewares");
|
|
13
14
|
var ServerSsrMode;
|
|
14
15
|
(function (ServerSsrMode) {
|
|
@@ -33,16 +34,23 @@ var ServerSsrMode;
|
|
|
33
34
|
*/
|
|
34
35
|
ServerSsrMode[ServerSsrMode["ExternalSsrMiddleware"] = 2] = "ExternalSsrMiddleware";
|
|
35
36
|
})(ServerSsrMode || (exports.ServerSsrMode = ServerSsrMode = {}));
|
|
37
|
+
async function createEncapsulateStyle() {
|
|
38
|
+
const { encapsulateStyle } = await (0, load_esm_1.loadEsmModule)('@angular/compiler');
|
|
39
|
+
const decoder = new TextDecoder('utf-8');
|
|
40
|
+
return (style, componentId) => {
|
|
41
|
+
return encapsulateStyle(decoder.decode(style), componentId);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
36
44
|
function createAngularSetupMiddlewaresPlugin(options) {
|
|
37
45
|
return {
|
|
38
46
|
name: 'vite:angular-setup-middlewares',
|
|
39
47
|
enforce: 'pre',
|
|
40
|
-
configureServer(server) {
|
|
41
|
-
const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets,
|
|
48
|
+
async configureServer(server) {
|
|
49
|
+
const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets, componentStyles, templateUpdates, ssrMode, } = options;
|
|
42
50
|
// Headers, assets and resources get handled first
|
|
43
51
|
server.middlewares.use((0, middlewares_1.createAngularHeadersMiddleware)(server));
|
|
44
52
|
server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(templateUpdates));
|
|
45
|
-
server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles,
|
|
53
|
+
server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles, componentStyles, await createEncapsulateStyle()));
|
|
46
54
|
extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware));
|
|
47
55
|
// Returning a function, installs middleware after the main transform middleware but
|
|
48
56
|
// before the built-in HTML middleware
|
|
@@ -16,4 +16,5 @@ export declare const useTypeChecking: boolean;
|
|
|
16
16
|
export declare const useJSONBuildLogs: boolean;
|
|
17
17
|
export declare const shouldOptimizeChunks: boolean;
|
|
18
18
|
export declare const useComponentStyleHmr: boolean;
|
|
19
|
+
export declare const useComponentTemplateHmr: boolean;
|
|
19
20
|
export declare const usePartialSsrBuild: boolean;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* found in the LICENSE file at https://angular.dev/license
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.usePartialSsrBuild = exports.useComponentStyleHmr = exports.shouldOptimizeChunks = exports.useJSONBuildLogs = exports.useTypeChecking = exports.shouldWatchRoot = exports.debugPerformance = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
|
|
10
|
+
exports.usePartialSsrBuild = exports.useComponentTemplateHmr = exports.useComponentStyleHmr = exports.shouldOptimizeChunks = exports.useJSONBuildLogs = exports.useTypeChecking = exports.shouldWatchRoot = exports.debugPerformance = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
|
|
11
11
|
const node_os_1 = require("node:os");
|
|
12
12
|
function isDisabled(variable) {
|
|
13
13
|
return variable === '0' || variable.toLowerCase() === 'false';
|
|
@@ -84,5 +84,7 @@ const optimizeChunksVariable = process.env['NG_BUILD_OPTIMIZE_CHUNKS'];
|
|
|
84
84
|
exports.shouldOptimizeChunks = isPresent(optimizeChunksVariable) && isEnabled(optimizeChunksVariable);
|
|
85
85
|
const hmrComponentStylesVariable = process.env['NG_HMR_CSTYLES'];
|
|
86
86
|
exports.useComponentStyleHmr = !isPresent(hmrComponentStylesVariable) || !isDisabled(hmrComponentStylesVariable);
|
|
87
|
+
const hmrComponentTemplateVariable = process.env['NG_HMR_TEMPLATES'];
|
|
88
|
+
exports.useComponentTemplateHmr = isPresent(hmrComponentTemplateVariable) && isEnabled(hmrComponentTemplateVariable);
|
|
87
89
|
const partialSsrBuildVariable = process.env['NG_BUILD_PARTIAL_SSR'];
|
|
88
90
|
exports.usePartialSsrBuild = isPresent(partialSsrBuildVariable) && isEnabled(partialSsrBuildVariable);
|
|
@@ -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-rc.
|
|
13
|
+
const VERSION = '19.0.0-rc.1';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|
|
@@ -0,0 +1,13 @@
|
|
|
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.IMPORT_EXEC_ARGV = void 0;
|
|
11
|
+
const node_path_1 = require("node:path");
|
|
12
|
+
const node_url_1 = require("node:url");
|
|
13
|
+
exports.IMPORT_EXEC_ARGV = '--import=' + (0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'register-hooks.js')).href;
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
9
|
-
import type
|
|
10
|
-
import type { PrerenderedRoutesRecord } from '../../tools/esbuild/bundler-execution-result';
|
|
9
|
+
import { type BuildOutputFile } from '../../tools/esbuild/bundler-context';
|
|
11
10
|
export declare const SERVER_APP_MANIFEST_FILENAME = "angular-app-manifest.mjs";
|
|
12
11
|
export declare const SERVER_APP_ENGINE_MANIFEST_FILENAME = "angular-app-engine-manifest.mjs";
|
|
13
12
|
/**
|
|
@@ -21,10 +20,8 @@ export declare const SERVER_APP_ENGINE_MANIFEST_FILENAME = "angular-app-engine-m
|
|
|
21
20
|
* includes settings for inlining locales and determining the output structure.
|
|
22
21
|
* @param baseHref - The base HREF for the application. This is used to set the base URL
|
|
23
22
|
* 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
23
|
*/
|
|
27
|
-
export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], baseHref: string | undefined
|
|
24
|
+
export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], baseHref: string | undefined): string;
|
|
28
25
|
/**
|
|
29
26
|
* Generates the server manifest for the standard Node.js environment.
|
|
30
27
|
*
|
|
@@ -44,7 +41,11 @@ export declare function generateAngularServerAppEngineManifest(i18nOptions: Norm
|
|
|
44
41
|
* @param locale - An optional string representing the locale or language code to be used for
|
|
45
42
|
* the application, helping with localization and rendering content specific to the locale.
|
|
46
43
|
*
|
|
47
|
-
* @returns
|
|
48
|
-
*
|
|
44
|
+
* @returns An object containing:
|
|
45
|
+
* - `manifestContent`: A string of the SSR manifest content.
|
|
46
|
+
* - `serverAssetsChunks`: An array of build output files containing the generated assets for the server.
|
|
49
47
|
*/
|
|
50
|
-
export declare function generateAngularServerAppManifest(additionalHtmlOutputFiles: Map<string, BuildOutputFile>, outputFiles: BuildOutputFile[], inlineCriticalCss: boolean, routes: readonly unknown[] | undefined, locale: string | undefined):
|
|
48
|
+
export declare function generateAngularServerAppManifest(additionalHtmlOutputFiles: Map<string, BuildOutputFile>, outputFiles: BuildOutputFile[], inlineCriticalCss: boolean, routes: readonly unknown[] | undefined, locale: string | undefined): {
|
|
49
|
+
manifestContent: string;
|
|
50
|
+
serverAssetsChunks: BuildOutputFile[];
|
|
51
|
+
};
|
|
@@ -10,7 +10,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.SERVER_APP_ENGINE_MANIFEST_FILENAME = exports.SERVER_APP_MANIFEST_FILENAME = void 0;
|
|
11
11
|
exports.generateAngularServerAppEngineManifest = generateAngularServerAppEngineManifest;
|
|
12
12
|
exports.generateAngularServerAppManifest = generateAngularServerAppManifest;
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
13
14
|
const options_1 = require("../../builders/application/options");
|
|
15
|
+
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
16
|
+
const utils_1 = require("../../tools/esbuild/utils");
|
|
14
17
|
exports.SERVER_APP_MANIFEST_FILENAME = 'angular-app-manifest.mjs';
|
|
15
18
|
exports.SERVER_APP_ENGINE_MANIFEST_FILENAME = 'angular-app-engine-manifest.mjs';
|
|
16
19
|
const MAIN_SERVER_OUTPUT_FILENAME = 'main.server.mjs';
|
|
@@ -43,10 +46,8 @@ function escapeUnsafeChars(str) {
|
|
|
43
46
|
* includes settings for inlining locales and determining the output structure.
|
|
44
47
|
* @param baseHref - The base HREF for the application. This is used to set the base URL
|
|
45
48
|
* 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
|
*/
|
|
49
|
-
function generateAngularServerAppEngineManifest(i18nOptions, baseHref
|
|
50
|
+
function generateAngularServerAppEngineManifest(i18nOptions, baseHref) {
|
|
50
51
|
const entryPointsContent = [];
|
|
51
52
|
if (i18nOptions.shouldInline) {
|
|
52
53
|
for (const locale of i18nOptions.inlineLocales) {
|
|
@@ -62,22 +63,10 @@ function generateAngularServerAppEngineManifest(i18nOptions, baseHref, perendere
|
|
|
62
63
|
else {
|
|
63
64
|
entryPointsContent.push(`['', () => import('./${MAIN_SERVER_OUTPUT_FILENAME}')]`);
|
|
64
65
|
}
|
|
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
66
|
const manifestContent = `
|
|
77
67
|
export default {
|
|
78
68
|
basePath: '${baseHref ?? '/'}',
|
|
79
69
|
entryPoints: new Map([${entryPointsContent.join(', \n')}]),
|
|
80
|
-
staticPathsHeaders: new Map([${staticHeaders.join(', \n')}]),
|
|
81
70
|
};
|
|
82
71
|
`;
|
|
83
72
|
return manifestContent;
|
|
@@ -101,16 +90,21 @@ export default {
|
|
|
101
90
|
* @param locale - An optional string representing the locale or language code to be used for
|
|
102
91
|
* the application, helping with localization and rendering content specific to the locale.
|
|
103
92
|
*
|
|
104
|
-
* @returns
|
|
105
|
-
*
|
|
93
|
+
* @returns An object containing:
|
|
94
|
+
* - `manifestContent`: A string of the SSR manifest content.
|
|
95
|
+
* - `serverAssetsChunks`: An array of build output files containing the generated assets for the server.
|
|
106
96
|
*/
|
|
107
97
|
function generateAngularServerAppManifest(additionalHtmlOutputFiles, outputFiles, inlineCriticalCss, routes, locale) {
|
|
98
|
+
const serverAssetsChunks = [];
|
|
108
99
|
const serverAssetsContent = [];
|
|
109
100
|
for (const file of [...additionalHtmlOutputFiles.values(), ...outputFiles]) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
101
|
+
const extension = (0, node_path_1.extname)(file.path);
|
|
102
|
+
if (extension === '.html' || (inlineCriticalCss && extension === '.css')) {
|
|
103
|
+
const jsChunkFilePath = `assets-chunks/${file.path.replace(/[./]/g, '_')}.mjs`;
|
|
104
|
+
const escapedContent = escapeUnsafeChars(file.text);
|
|
105
|
+
serverAssetsChunks.push((0, utils_1.createOutputFile)(jsChunkFilePath, `export default \`${escapedContent}\`;`, bundler_context_1.BuildOutputFileType.ServerApplication));
|
|
106
|
+
const contentLength = Buffer.byteLength(escapedContent);
|
|
107
|
+
serverAssetsContent.push(`['${file.path}', {size: ${contentLength}, hash: '${file.hash}', text: () => import('./${jsChunkFilePath}').then(m => m.default)}]`);
|
|
114
108
|
}
|
|
115
109
|
}
|
|
116
110
|
const manifestContent = `
|
|
@@ -118,9 +112,9 @@ export default {
|
|
|
118
112
|
bootstrap: () => import('./main.server.mjs').then(m => m.default),
|
|
119
113
|
inlineCriticalCss: ${inlineCriticalCss},
|
|
120
114
|
routes: ${JSON.stringify(routes, undefined, 2)},
|
|
121
|
-
assets: new Map([${serverAssetsContent.join(', \n')}]),
|
|
115
|
+
assets: new Map([\n${serverAssetsContent.join(', \n')}\n]),
|
|
122
116
|
locale: ${locale !== undefined ? `'${locale}'` : undefined},
|
|
123
117
|
};
|
|
124
118
|
`;
|
|
125
|
-
return manifestContent;
|
|
119
|
+
return { manifestContent, serverAssetsChunks };
|
|
126
120
|
}
|
|
@@ -10,12 +10,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.prerenderPages = prerenderPages;
|
|
11
11
|
const promises_1 = require("node:fs/promises");
|
|
12
12
|
const node_path_1 = require("node:path");
|
|
13
|
-
const node_url_1 = require("node:url");
|
|
14
13
|
const schema_1 = require("../../builders/application/schema");
|
|
15
14
|
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
16
15
|
const error_1 = require("../error");
|
|
17
16
|
const url_1 = require("../url");
|
|
18
17
|
const worker_pool_1 = require("../worker-pool");
|
|
18
|
+
const utils_1 = require("./esm-in-memory-loader/utils");
|
|
19
19
|
const models_1 = require("./models");
|
|
20
20
|
async function prerenderPages(workspaceRoot, baseHref, appShellOptions, prerenderOptions, outputFiles, assets, outputMode, sourcemap = false, maxThreads = 1) {
|
|
21
21
|
const outputFilesForWorker = {};
|
|
@@ -104,11 +104,7 @@ async function prerenderPages(workspaceRoot, baseHref, appShellOptions, prerende
|
|
|
104
104
|
async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxThreads, workspaceRoot, outputFilesForWorker, assetFilesForWorker, appShellOptions, outputMode) {
|
|
105
105
|
const output = {};
|
|
106
106
|
const errors = [];
|
|
107
|
-
const workerExecArgv = [
|
|
108
|
-
'--import',
|
|
109
|
-
// Loader cannot be an absolute path on Windows.
|
|
110
|
-
(0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'esm-in-memory-loader/register-hooks.js')).href,
|
|
111
|
-
];
|
|
107
|
+
const workerExecArgv = [utils_1.IMPORT_EXEC_ARGV];
|
|
112
108
|
if (sourcemap) {
|
|
113
109
|
workerExecArgv.push('--enable-source-maps');
|
|
114
110
|
}
|
|
@@ -129,8 +125,10 @@ async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxTh
|
|
|
129
125
|
const appShellRoute = appShellOptions && addLeadingSlash(appShellOptions.route);
|
|
130
126
|
const baseHrefWithLeadingSlash = addLeadingSlash(baseHref);
|
|
131
127
|
for (const { route, redirectTo, renderMode } of serializableRouteTreeNode) {
|
|
132
|
-
// Remove base href from file output path.
|
|
133
|
-
const routeWithoutBaseHref =
|
|
128
|
+
// Remove the base href from the file output path.
|
|
129
|
+
const routeWithoutBaseHref = addTrailingSlash(route).startsWith(baseHrefWithLeadingSlash)
|
|
130
|
+
? addLeadingSlash(route.slice(baseHrefWithLeadingSlash.length - 1))
|
|
131
|
+
: route;
|
|
134
132
|
const outPath = node_path_1.posix.join(removeLeadingSlash(routeWithoutBaseHref), 'index.html');
|
|
135
133
|
if (typeof redirectTo === 'string') {
|
|
136
134
|
output[outPath] = { content: generateRedirectStaticPage(redirectTo), appShellRoute: false };
|
|
@@ -167,6 +165,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
|
|
|
167
165
|
const routes = [];
|
|
168
166
|
if (appShellOptions) {
|
|
169
167
|
routes.push({
|
|
168
|
+
renderMode: models_1.RouteRenderMode.AppShell,
|
|
170
169
|
route: (0, url_1.urlJoin)(baseHref, appShellOptions.route),
|
|
171
170
|
});
|
|
172
171
|
}
|
|
@@ -174,6 +173,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
|
|
|
174
173
|
const routesFromFile = (await (0, promises_1.readFile)(routesFile, 'utf8')).split(/\r?\n/);
|
|
175
174
|
for (const route of routesFromFile) {
|
|
176
175
|
routes.push({
|
|
176
|
+
renderMode: models_1.RouteRenderMode.Prerender,
|
|
177
177
|
route: (0, url_1.urlJoin)(baseHref, route.trim()),
|
|
178
178
|
});
|
|
179
179
|
}
|
|
@@ -181,11 +181,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
|
|
|
181
181
|
if (!discoverRoutes) {
|
|
182
182
|
return { errors: [], serializedRouteTree: routes };
|
|
183
183
|
}
|
|
184
|
-
const workerExecArgv = [
|
|
185
|
-
'--import',
|
|
186
|
-
// Loader cannot be an absolute path on Windows.
|
|
187
|
-
(0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'esm-in-memory-loader/register-hooks.js')).href,
|
|
188
|
-
];
|
|
184
|
+
const workerExecArgv = [utils_1.IMPORT_EXEC_ARGV];
|
|
189
185
|
if (sourcemap) {
|
|
190
186
|
workerExecArgv.push('--enable-source-maps');
|
|
191
187
|
}
|
|
@@ -203,7 +199,17 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
|
|
|
203
199
|
});
|
|
204
200
|
try {
|
|
205
201
|
const { serializedRouteTree, errors } = await renderWorker.run({});
|
|
206
|
-
|
|
202
|
+
if (!routes.length) {
|
|
203
|
+
return { errors, serializedRouteTree };
|
|
204
|
+
}
|
|
205
|
+
// Merge the routing trees
|
|
206
|
+
const uniqueRoutes = new Map();
|
|
207
|
+
for (const item of [...routes, ...serializedRouteTree]) {
|
|
208
|
+
if (!uniqueRoutes.has(item.route)) {
|
|
209
|
+
uniqueRoutes.set(item.route, item);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { errors, serializedRouteTree: Array.from(uniqueRoutes.values()) };
|
|
207
213
|
}
|
|
208
214
|
catch (err) {
|
|
209
215
|
(0, error_1.assertIsError)(err);
|
|
@@ -219,10 +225,13 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
|
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
227
|
function addLeadingSlash(value) {
|
|
222
|
-
return value
|
|
228
|
+
return value[0] === '/' ? value : '/' + value;
|
|
229
|
+
}
|
|
230
|
+
function addTrailingSlash(url) {
|
|
231
|
+
return url[url.length - 1] === '/' ? url : `${url}/`;
|
|
223
232
|
}
|
|
224
233
|
function removeLeadingSlash(value) {
|
|
225
|
-
return value
|
|
234
|
+
return value[0] === '/' ? value.slice(1) : value;
|
|
226
235
|
}
|
|
227
236
|
/**
|
|
228
237
|
* Generates a static HTML page with a meta refresh tag to redirect the user to a specified URL.
|
|
@@ -21,8 +21,10 @@ let serverURL = launch_server_1.DEFAULT_URL;
|
|
|
21
21
|
*/
|
|
22
22
|
async function renderPage({ url }) {
|
|
23
23
|
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = await (0, load_esm_from_memory_1.loadEsmModuleFromMemory)('./main.server.mjs');
|
|
24
|
-
const angularServerApp = getOrCreateAngularServerApp(
|
|
25
|
-
|
|
24
|
+
const angularServerApp = getOrCreateAngularServerApp({
|
|
25
|
+
allowStaticRouteRender: true,
|
|
26
|
+
});
|
|
27
|
+
const response = await angularServerApp.handle(new Request(new URL(url, serverURL), { signal: AbortSignal.timeout(30_000) }));
|
|
26
28
|
return response ? response.text() : null;
|
|
27
29
|
}
|
|
28
30
|
async function initialize() {
|