@angular/build 19.0.0-next.2 → 19.0.0-next.3
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 +10 -10
- package/src/builders/application/execute-post-bundle.js +29 -18
- package/src/builders/application/i18n.js +2 -11
- package/src/builders/application/options.d.ts +11 -0
- package/src/builders/application/options.js +23 -1
- package/src/builders/application/setup-bundling.js +7 -7
- 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 +2 -1
- package/src/builders/dev-server/vite-server.js +13 -2
- package/src/tools/esbuild/angular/file-reference-tracker.d.ts +1 -1
- package/src/tools/esbuild/application-code-bundle.d.ts +1 -6
- package/src/tools/esbuild/application-code-bundle.js +105 -70
- package/src/tools/esbuild/bundler-context.js +14 -10
- package/src/tools/esbuild/cache.d.ts +1 -1
- package/src/tools/esbuild/utils.d.ts +9 -0
- package/src/tools/esbuild/utils.js +14 -0
- package/src/tools/sass/sass-service.js +9 -4
- package/src/tools/vite/angular-memory-plugin.js +2 -2
- package/src/tools/vite/middlewares/ssr-middleware.d.ts +1 -4
- package/src/tools/vite/middlewares/ssr-middleware.js +25 -38
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/server-rendering/fetch-patch.js +4 -5
- package/src/utils/server-rendering/load-esm-from-memory.d.ts +12 -2
- package/src/utils/server-rendering/manifest.d.ts +44 -0
- package/src/utils/server-rendering/manifest.js +88 -0
- package/src/utils/server-rendering/prerender.d.ts +22 -2
- package/src/utils/server-rendering/prerender.js +51 -40
- package/src/utils/server-rendering/render-worker.d.ts +7 -8
- package/src/utils/server-rendering/render-worker.js +10 -13
- package/src/utils/server-rendering/routes-extractor-worker.d.ts +2 -6
- package/src/utils/server-rendering/routes-extractor-worker.js +3 -34
- package/src/utils/server-rendering/main-bundle-exports.d.ts +0 -27
- package/src/utils/server-rendering/main-bundle-exports.js +0 -9
- package/src/utils/server-rendering/render-page.d.ts +0 -26
- package/src/utils/server-rendering/render-page.js +0 -114
|
@@ -12,12 +12,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.createBrowserCodeBundleOptions = createBrowserCodeBundleOptions;
|
|
14
14
|
exports.createBrowserPolyfillBundleOptions = createBrowserPolyfillBundleOptions;
|
|
15
|
-
exports.createServerCodeBundleOptions = createServerCodeBundleOptions;
|
|
16
15
|
exports.createServerPolyfillBundleOptions = createServerPolyfillBundleOptions;
|
|
16
|
+
exports.createServerMainCodeBundleOptions = createServerMainCodeBundleOptions;
|
|
17
17
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
18
18
|
const node_crypto_1 = require("node:crypto");
|
|
19
19
|
const node_path_1 = require("node:path");
|
|
20
20
|
const environment_options_1 = require("../../utils/environment-options");
|
|
21
|
+
const manifest_1 = require("../../utils/server-rendering/manifest");
|
|
21
22
|
const compiler_plugin_1 = require("./angular/compiler-plugin");
|
|
22
23
|
const compiler_plugin_options_1 = require("./compiler-plugin-options");
|
|
23
24
|
const external_packages_plugin_1 = require("./external-packages-plugin");
|
|
@@ -110,29 +111,28 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
110
111
|
// cannot be used with fully incremental bundling yet.
|
|
111
112
|
return hasTypeScriptEntries ? buildOptions : () => buildOptions;
|
|
112
113
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
115
|
+
const serverPolyfills = [];
|
|
116
|
+
const polyfillsFromConfig = new Set(options.polyfills);
|
|
117
|
+
if (!(0, utils_1.isZonelessApp)(options.polyfills)) {
|
|
118
|
+
serverPolyfills.push('zone.js/node');
|
|
119
|
+
}
|
|
120
|
+
if (polyfillsFromConfig.has('@angular/localize') ||
|
|
121
|
+
polyfillsFromConfig.has('@angular/localize/init')) {
|
|
122
|
+
serverPolyfills.push('@angular/localize/init');
|
|
123
|
+
}
|
|
124
|
+
serverPolyfills.push('@angular/platform-server/init');
|
|
125
|
+
const namespace = 'angular:polyfills-server';
|
|
126
|
+
const polyfillBundleOptions = getEsBuildCommonPolyfillsOptions({
|
|
127
|
+
...options,
|
|
128
|
+
polyfills: serverPolyfills,
|
|
129
|
+
}, namespace, false, sourceFileCache);
|
|
130
|
+
if (!polyfillBundleOptions) {
|
|
131
|
+
return;
|
|
130
132
|
}
|
|
131
|
-
const zoneless = (0, utils_1.isZonelessApp)(polyfills);
|
|
132
133
|
const buildOptions = {
|
|
133
|
-
...
|
|
134
|
+
...polyfillBundleOptions,
|
|
134
135
|
platform: 'node',
|
|
135
|
-
splitting: true,
|
|
136
136
|
outExtension: { '.js': '.mjs' },
|
|
137
137
|
// Note: `es2015` is needed for RxJS v6. If not specified, `module` would
|
|
138
138
|
// match and the ES5 distribution would be bundled and ends up breaking at
|
|
@@ -140,14 +140,45 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
140
140
|
// More details: https://github.com/angular/angular-cli/issues/25405.
|
|
141
141
|
mainFields: ['es2020', 'es2015', 'module', 'main'],
|
|
142
142
|
entryNames: '[name]',
|
|
143
|
-
target,
|
|
144
143
|
banner: {
|
|
145
|
-
js:
|
|
144
|
+
js: [
|
|
145
|
+
// Note: Needed as esbuild does not provide require shims / proxy from ESModules.
|
|
146
|
+
// See: https://github.com/evanw/esbuild/issues/1921.
|
|
147
|
+
`import { createRequire } from 'node:module';`,
|
|
148
|
+
`globalThis['require'] ??= createRequire(import.meta.url);`,
|
|
149
|
+
].join('\n'),
|
|
150
|
+
},
|
|
151
|
+
target,
|
|
152
|
+
entryPoints: {
|
|
153
|
+
'polyfills.server': namespace,
|
|
146
154
|
},
|
|
155
|
+
};
|
|
156
|
+
return () => buildOptions;
|
|
157
|
+
}
|
|
158
|
+
function createServerMainCodeBundleOptions(options, target, sourceFileCache) {
|
|
159
|
+
const { serverEntryPoint: mainServerEntryPoint, workspaceRoot, externalPackages, ssrOptions, polyfills, } = options;
|
|
160
|
+
(0, node_assert_1.default)(mainServerEntryPoint, 'createServerCodeBundleOptions should not be called without a defined serverEntryPoint.');
|
|
161
|
+
const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
|
|
162
|
+
const mainServerNamespace = 'angular:main-server';
|
|
163
|
+
const mainServerInjectPolyfillsNamespace = 'angular:main-server-inject-polyfills';
|
|
164
|
+
const mainServerInjectManifestNamespace = 'angular:main-server-inject-manifest';
|
|
165
|
+
const zoneless = (0, utils_1.isZonelessApp)(polyfills);
|
|
166
|
+
const entryPoints = {
|
|
167
|
+
'main.server': mainServerNamespace,
|
|
168
|
+
};
|
|
169
|
+
const ssrEntryPoint = ssrOptions?.entry;
|
|
170
|
+
if (ssrEntryPoint) {
|
|
171
|
+
// Old behavior: 'server.ts' was bundled together with the SSR (Server-Side Rendering) code.
|
|
172
|
+
// This approach combined server-side logic and rendering into a single bundle.
|
|
173
|
+
entryPoints['server'] = ssrEntryPoint;
|
|
174
|
+
}
|
|
175
|
+
const buildOptions = {
|
|
176
|
+
...getEsBuildServerCommonOptions(options),
|
|
177
|
+
target,
|
|
178
|
+
inject: [mainServerInjectPolyfillsNamespace, mainServerInjectManifestNamespace],
|
|
147
179
|
entryPoints,
|
|
148
180
|
supported: (0, utils_1.getFeatureSupport)(target, zoneless),
|
|
149
181
|
plugins: [
|
|
150
|
-
(0, loader_import_attribute_plugin_1.createLoaderImportAttributePlugin)(),
|
|
151
182
|
(0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: sourceFileCache?.loadResultCache }),
|
|
152
183
|
(0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
|
|
153
184
|
(0, compiler_plugin_1.createCompilerPlugin)(
|
|
@@ -164,20 +195,49 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
164
195
|
else {
|
|
165
196
|
buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
|
|
166
197
|
}
|
|
198
|
+
// Mark manifest and polyfills file as external as these are generated by a different bundle step.
|
|
199
|
+
(buildOptions.external ??= []).push(...utils_1.SERVER_GENERATED_EXTERNALS);
|
|
167
200
|
buildOptions.plugins.push((0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
201
|
+
namespace: mainServerInjectPolyfillsNamespace,
|
|
202
|
+
cache: sourceFileCache?.loadResultCache,
|
|
203
|
+
loadContent: () => ({
|
|
204
|
+
contents: `import './polyfills.server.mjs';`,
|
|
205
|
+
loader: 'js',
|
|
206
|
+
resolveDir: workspaceRoot,
|
|
207
|
+
}),
|
|
208
|
+
}), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
209
|
+
namespace: mainServerInjectManifestNamespace,
|
|
210
|
+
cache: sourceFileCache?.loadResultCache,
|
|
211
|
+
loadContent: async () => {
|
|
212
|
+
const contents = [
|
|
213
|
+
// Configure `@angular/ssr` manifest.
|
|
214
|
+
`import manifest from './${manifest_1.SERVER_APP_MANIFEST_FILENAME}';`,
|
|
215
|
+
`import { ɵsetAngularAppManifest } from '@angular/ssr';`,
|
|
216
|
+
`ɵsetAngularAppManifest(manifest);`,
|
|
217
|
+
];
|
|
218
|
+
return {
|
|
219
|
+
contents: contents.join('\n'),
|
|
220
|
+
loader: 'js',
|
|
221
|
+
resolveDir: workspaceRoot,
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
}), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
168
225
|
namespace: mainServerNamespace,
|
|
169
226
|
cache: sourceFileCache?.loadResultCache,
|
|
170
227
|
loadContent: async () => {
|
|
228
|
+
const mainServerEntryPointJsImport = entryFileToWorkspaceRelative(workspaceRoot, mainServerEntryPoint);
|
|
171
229
|
const contents = [
|
|
172
|
-
|
|
173
|
-
`export {
|
|
230
|
+
// Re-export all symbols including default export from 'main.server.ts'
|
|
231
|
+
`export { default } from '${mainServerEntryPointJsImport}';`,
|
|
232
|
+
`export * from '${mainServerEntryPointJsImport}';`,
|
|
233
|
+
// Add @angular/ssr exports
|
|
234
|
+
`export {
|
|
235
|
+
ɵServerRenderContext,
|
|
236
|
+
ɵdestroyAngularServerApp,
|
|
237
|
+
ɵextractRoutesAndCreateRouteTree,
|
|
238
|
+
ɵgetOrCreateAngularServerApp,
|
|
239
|
+
} from '@angular/ssr';`,
|
|
174
240
|
];
|
|
175
|
-
if (watch) {
|
|
176
|
-
contents.push(`export { ɵresetCompiledComponents } from '@angular/core';`);
|
|
177
|
-
}
|
|
178
|
-
if (prerenderOptions?.discoverRoutes) {
|
|
179
|
-
contents.push(`export { ɵgetRoutesFromAngularRouterConfig } from '@angular/ssr';`);
|
|
180
|
-
}
|
|
181
241
|
return {
|
|
182
242
|
contents: contents.join('\n'),
|
|
183
243
|
loader: 'js',
|
|
@@ -190,27 +250,9 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
190
250
|
}
|
|
191
251
|
return buildOptions;
|
|
192
252
|
}
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (!(0, utils_1.isZonelessApp)(options.polyfills)) {
|
|
197
|
-
serverPolyfills.push('zone.js/node');
|
|
198
|
-
}
|
|
199
|
-
if (polyfillsFromConfig.has('@angular/localize') ||
|
|
200
|
-
polyfillsFromConfig.has('@angular/localize/init')) {
|
|
201
|
-
serverPolyfills.push('@angular/localize/init');
|
|
202
|
-
}
|
|
203
|
-
serverPolyfills.push('@angular/platform-server/init');
|
|
204
|
-
const namespace = 'angular:polyfills-server';
|
|
205
|
-
const polyfillBundleOptions = getEsBuildCommonPolyfillsOptions({
|
|
206
|
-
...options,
|
|
207
|
-
polyfills: serverPolyfills,
|
|
208
|
-
}, namespace, false, sourceFileCache);
|
|
209
|
-
if (!polyfillBundleOptions) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const buildOptions = {
|
|
213
|
-
...polyfillBundleOptions,
|
|
253
|
+
function getEsBuildServerCommonOptions(options) {
|
|
254
|
+
return {
|
|
255
|
+
...getEsBuildCommonOptions(options),
|
|
214
256
|
platform: 'node',
|
|
215
257
|
outExtension: { '.js': '.mjs' },
|
|
216
258
|
// Note: `es2015` is needed for RxJS v6. If not specified, `module` would
|
|
@@ -219,31 +261,18 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
219
261
|
// More details: https://github.com/angular/angular-cli/issues/25405.
|
|
220
262
|
mainFields: ['es2020', 'es2015', 'module', 'main'],
|
|
221
263
|
entryNames: '[name]',
|
|
222
|
-
banner: {
|
|
223
|
-
js: [
|
|
224
|
-
// Note: Needed as esbuild does not provide require shims / proxy from ESModules.
|
|
225
|
-
// See: https://github.com/evanw/esbuild/issues/1921.
|
|
226
|
-
`import { createRequire } from 'node:module';`,
|
|
227
|
-
`globalThis['require'] ??= createRequire(import.meta.url);`,
|
|
228
|
-
].join('\n'),
|
|
229
|
-
},
|
|
230
|
-
target,
|
|
231
|
-
entryPoints: {
|
|
232
|
-
'polyfills.server': namespace,
|
|
233
|
-
},
|
|
234
264
|
};
|
|
235
|
-
return () => buildOptions;
|
|
236
265
|
}
|
|
237
266
|
function getEsBuildCommonOptions(options) {
|
|
238
|
-
const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, } = options;
|
|
267
|
+
const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, } = options;
|
|
239
268
|
// Ensure unique hashes for i18n translation changes when using post-process inlining.
|
|
240
269
|
// This hash value is added as a footer to each file and ensures that the output file names (with hashes)
|
|
241
270
|
// change when translation files have changed. If this is not done the post processed files may have
|
|
242
271
|
// different content but would retain identical production file names which would lead to browser caching problems.
|
|
243
272
|
let footer;
|
|
244
|
-
if (
|
|
273
|
+
if (i18nOptions.shouldInline) {
|
|
245
274
|
// Update file hashes to include translation file content
|
|
246
|
-
const i18nHash = Object.values(
|
|
275
|
+
const i18nHash = Object.values(i18nOptions.locales).reduce((data, locale) => data + locale.files.map((file) => file.integrity || '').join('|'), '');
|
|
247
276
|
footer = { js: `/**i18n:${(0, node_crypto_1.createHash)('sha256').update(i18nHash).digest('hex')}*/` };
|
|
248
277
|
}
|
|
249
278
|
return {
|
|
@@ -267,7 +296,7 @@ function getEsBuildCommonOptions(options) {
|
|
|
267
296
|
splitting: true,
|
|
268
297
|
chunkNames: options.namedChunks ? '[name]-[hash]' : 'chunk-[hash]',
|
|
269
298
|
tsconfig,
|
|
270
|
-
external: externalDependencies,
|
|
299
|
+
external: externalDependencies ? [...externalDependencies] : undefined,
|
|
271
300
|
write: false,
|
|
272
301
|
preserveSymlinks,
|
|
273
302
|
define: {
|
|
@@ -360,3 +389,9 @@ function getEsBuildCommonPolyfillsOptions(options, namespace, tryToResolvePolyfi
|
|
|
360
389
|
}));
|
|
361
390
|
return buildOptions;
|
|
362
391
|
}
|
|
392
|
+
function entryFileToWorkspaceRelative(workspaceRoot, entryFile) {
|
|
393
|
+
return ('./' +
|
|
394
|
+
(0, node_path_1.relative)(workspaceRoot, entryFile)
|
|
395
|
+
.replace(/.[mc]?ts$/, '')
|
|
396
|
+
.replace(/\\/g, '/'));
|
|
397
|
+
}
|
|
@@ -138,6 +138,7 @@ class BundlerContext {
|
|
|
138
138
|
}
|
|
139
139
|
return result;
|
|
140
140
|
}
|
|
141
|
+
// eslint-disable-next-line max-lines-per-function
|
|
141
142
|
async #performBundle() {
|
|
142
143
|
// Create esbuild options if not present
|
|
143
144
|
if (this.#esbuildOptions === undefined) {
|
|
@@ -165,12 +166,6 @@ class BundlerContext {
|
|
|
165
166
|
// For non-incremental builds, perform a single build
|
|
166
167
|
result = await (0, esbuild_1.build)(this.#esbuildOptions);
|
|
167
168
|
}
|
|
168
|
-
if (this.#platformIsServer) {
|
|
169
|
-
for (const entry of Object.values(result.metafile.outputs)) {
|
|
170
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
|
-
entry['ng-platform-server'] = true;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
169
|
}
|
|
175
170
|
catch (failure) {
|
|
176
171
|
// Build failures will throw an exception which contains errors/warnings
|
|
@@ -280,6 +275,7 @@ class BundlerContext {
|
|
|
280
275
|
for (const { imports } of Object.values(result.metafile.outputs)) {
|
|
281
276
|
for (const importData of imports) {
|
|
282
277
|
if (!importData.external ||
|
|
278
|
+
utils_1.SERVER_GENERATED_EXTERNALS.has(importData.path) ||
|
|
283
279
|
(importData.kind !== 'import-statement' &&
|
|
284
280
|
importData.kind !== 'dynamic-import' &&
|
|
285
281
|
importData.kind !== 'require-call')) {
|
|
@@ -295,13 +291,21 @@ class BundlerContext {
|
|
|
295
291
|
if (!/\.([cm]?js|css|wasm)(\.map)?$/i.test(file.path)) {
|
|
296
292
|
fileType = BuildOutputFileType.Media;
|
|
297
293
|
}
|
|
294
|
+
else if (this.#platformIsServer) {
|
|
295
|
+
fileType = BuildOutputFileType.Server;
|
|
296
|
+
}
|
|
298
297
|
else {
|
|
299
|
-
fileType =
|
|
300
|
-
? BuildOutputFileType.Server
|
|
301
|
-
: BuildOutputFileType.Browser;
|
|
298
|
+
fileType = BuildOutputFileType.Browser;
|
|
302
299
|
}
|
|
303
300
|
return (0, utils_1.convertOutputFile)(file, fileType);
|
|
304
301
|
});
|
|
302
|
+
let externalConfiguration = this.#esbuildOptions.external;
|
|
303
|
+
if (this.#platformIsServer && externalConfiguration) {
|
|
304
|
+
externalConfiguration = externalConfiguration.filter((dep) => !utils_1.SERVER_GENERATED_EXTERNALS.has(dep));
|
|
305
|
+
if (!externalConfiguration.length) {
|
|
306
|
+
externalConfiguration = undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
305
309
|
// Return the successful build results
|
|
306
310
|
return {
|
|
307
311
|
...result,
|
|
@@ -310,7 +314,7 @@ class BundlerContext {
|
|
|
310
314
|
externalImports: {
|
|
311
315
|
[this.#platformIsServer ? 'server' : 'browser']: externalImports,
|
|
312
316
|
},
|
|
313
|
-
externalConfiguration
|
|
317
|
+
externalConfiguration,
|
|
314
318
|
errors: undefined,
|
|
315
319
|
};
|
|
316
320
|
}
|
|
@@ -84,5 +84,5 @@ export declare class MemoryCache<V> extends Cache<V, Map<string, V>> {
|
|
|
84
84
|
* Provides all the values currently present in the cache instance.
|
|
85
85
|
* @returns An iterable of all values in the cache.
|
|
86
86
|
*/
|
|
87
|
-
values():
|
|
87
|
+
values(): MapIterator<V>;
|
|
88
88
|
}
|
|
@@ -47,3 +47,12 @@ export declare function logMessages(logger: BuilderContext['logger'], executionR
|
|
|
47
47
|
*/
|
|
48
48
|
export declare function isZonelessApp(polyfills: string[] | undefined): boolean;
|
|
49
49
|
export declare function getEntryPointName(entryPoint: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* A set of server-generated dependencies that are treated as external.
|
|
52
|
+
*
|
|
53
|
+
* These dependencies are marked as external because they are produced by a
|
|
54
|
+
* separate bundling process and are not included in the primary bundle. This
|
|
55
|
+
* ensures that these generated files are resolved from an external source rather
|
|
56
|
+
* than being part of the main bundle.
|
|
57
|
+
*/
|
|
58
|
+
export declare const SERVER_GENERATED_EXTERNALS: Set<string>;
|
|
@@ -7,6 +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.SERVER_GENERATED_EXTERNALS = void 0;
|
|
10
11
|
exports.logBuildStats = logBuildStats;
|
|
11
12
|
exports.getChunkNameFromMetafile = getChunkNameFromMetafile;
|
|
12
13
|
exports.calculateEstimatedTransferSizes = calculateEstimatedTransferSizes;
|
|
@@ -29,6 +30,7 @@ const node_path_1 = require("node:path");
|
|
|
29
30
|
const node_url_1 = require("node:url");
|
|
30
31
|
const node_zlib_1 = require("node:zlib");
|
|
31
32
|
const semver_1 = require("semver");
|
|
33
|
+
const manifest_1 = require("../../utils/server-rendering/manifest");
|
|
32
34
|
const stats_table_1 = require("../../utils/stats-table");
|
|
33
35
|
const bundler_context_1 = require("./bundler-context");
|
|
34
36
|
function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, changedFiles, estimatedTransferSizes, ssrOutputEnabled, verbose) {
|
|
@@ -385,3 +387,15 @@ function getEntryPointName(entryPoint) {
|
|
|
385
387
|
.replace(/\.[cm]?[jt]s$/, '')
|
|
386
388
|
.replace(/[\\/.]/g, '-');
|
|
387
389
|
}
|
|
390
|
+
/**
|
|
391
|
+
* A set of server-generated dependencies that are treated as external.
|
|
392
|
+
*
|
|
393
|
+
* These dependencies are marked as external because they are produced by a
|
|
394
|
+
* separate bundling process and are not included in the primary bundle. This
|
|
395
|
+
* ensures that these generated files are resolved from an external source rather
|
|
396
|
+
* than being part of the main bundle.
|
|
397
|
+
*/
|
|
398
|
+
exports.SERVER_GENERATED_EXTERNALS = new Set([
|
|
399
|
+
'./polyfills.server.mjs',
|
|
400
|
+
'./' + manifest_1.SERVER_APP_MANIFEST_FILENAME,
|
|
401
|
+
]);
|
|
@@ -34,17 +34,22 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
34
34
|
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
35
35
|
env.hasError = true;
|
|
36
36
|
}
|
|
37
|
+
var r, s = 0;
|
|
37
38
|
function next() {
|
|
38
|
-
while (env.stack.
|
|
39
|
-
var rec = env.stack.pop();
|
|
39
|
+
while (r = env.stack.pop()) {
|
|
40
40
|
try {
|
|
41
|
-
|
|
42
|
-
if (
|
|
41
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
42
|
+
if (r.dispose) {
|
|
43
|
+
var result = r.dispose.call(r.value);
|
|
44
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
45
|
+
}
|
|
46
|
+
else s |= 1;
|
|
43
47
|
}
|
|
44
48
|
catch (e) {
|
|
45
49
|
fail(e);
|
|
46
50
|
}
|
|
47
51
|
}
|
|
52
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
48
53
|
if (env.hasError) throw env.error;
|
|
49
54
|
}
|
|
50
55
|
return next();
|
|
@@ -82,10 +82,10 @@ function createAngularMemoryPlugin(options) {
|
|
|
82
82
|
// Returning a function, installs middleware after the main transform middleware but
|
|
83
83
|
// before the built-in HTML middleware
|
|
84
84
|
return () => {
|
|
85
|
-
server.middlewares.use(middlewares_1.angularHtmlFallbackMiddleware);
|
|
86
85
|
if (ssr) {
|
|
87
|
-
server.middlewares.use((0, middlewares_1.createAngularSSRMiddleware)(server,
|
|
86
|
+
server.middlewares.use((0, middlewares_1.createAngularSSRMiddleware)(server, indexHtmlTransformer));
|
|
88
87
|
}
|
|
88
|
+
server.middlewares.use(middlewares_1.angularHtmlFallbackMiddleware);
|
|
89
89
|
server.middlewares.use((0, middlewares_1.createAngularIndexHtmlMiddleware)(server, outputFiles, indexHtmlTransformer));
|
|
90
90
|
};
|
|
91
91
|
},
|
|
@@ -6,7 +6,4 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import type { Connect, ViteDevServer } from 'vite';
|
|
9
|
-
export declare function createAngularSSRMiddleware(server: ViteDevServer,
|
|
10
|
-
contents: Uint8Array;
|
|
11
|
-
servable: boolean;
|
|
12
|
-
}>, indexHtmlTransformer?: (content: string) => Promise<string>): Connect.NextHandleFunction;
|
|
9
|
+
export declare function createAngularSSRMiddleware(server: ViteDevServer, indexHtmlTransformer?: (content: string) => Promise<string>): Connect.NextHandleFunction;
|
|
@@ -8,49 +8,36 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.createAngularSSRMiddleware = createAngularSSRMiddleware;
|
|
11
|
-
const render_page_1 = require("../../../utils/server-rendering/render-page");
|
|
12
11
|
const utils_1 = require("../utils");
|
|
13
|
-
function createAngularSSRMiddleware(server,
|
|
12
|
+
function createAngularSSRMiddleware(server, indexHtmlTransformer) {
|
|
13
|
+
let cachedAngularServerApp;
|
|
14
14
|
return function (req, res, next) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Skip if path is not defined.
|
|
18
|
-
!url ||
|
|
19
|
-
// Skip if path is like a file.
|
|
20
|
-
// NOTE: We use a mime type lookup to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
|
|
21
|
-
(0, utils_1.lookupMimeTypeFromRequest)(url)) {
|
|
22
|
-
next();
|
|
23
|
-
return;
|
|
15
|
+
if (req.url === undefined) {
|
|
16
|
+
return next();
|
|
24
17
|
}
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
18
|
+
const resolvedUrls = server.resolvedUrls;
|
|
19
|
+
const baseUrl = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
20
|
+
const url = new URL(req.url, baseUrl);
|
|
21
|
+
(async () => {
|
|
22
|
+
const { ɵgetOrCreateAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
|
|
23
|
+
const angularServerApp = ɵgetOrCreateAngularServerApp();
|
|
24
|
+
// Only Add the transform hook only if it's a different instance.
|
|
25
|
+
if (cachedAngularServerApp !== angularServerApp) {
|
|
26
|
+
angularServerApp.hooks.on('html:transform:pre', async ({ html }) => {
|
|
27
|
+
const processedHtml = await server.transformIndexHtml(url.pathname, html);
|
|
28
|
+
return indexHtmlTransformer?.(processedHtml) ?? processedHtml;
|
|
29
|
+
});
|
|
30
|
+
cachedAngularServerApp = angularServerApp;
|
|
31
|
+
}
|
|
32
|
+
const response = await angularServerApp.render(new Request(url, { signal: AbortSignal.timeout(30_000) }), undefined);
|
|
33
|
+
return response?.text();
|
|
34
|
+
})()
|
|
35
|
+
.then((content) => {
|
|
36
|
+
if (typeof content !== 'string') {
|
|
37
|
+
return next();
|
|
37
38
|
}
|
|
38
|
-
const { content: ssrContent } = await (0, render_page_1.renderPage)({
|
|
39
|
-
document: processedHtml,
|
|
40
|
-
route: new URL(req.originalUrl ?? '/', baseUrl).toString(),
|
|
41
|
-
serverContext: 'ssr',
|
|
42
|
-
loadBundle: (uri) =>
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
-
server.ssrLoadModule(uri.slice(1)),
|
|
45
|
-
// Files here are only needed for critical CSS inlining.
|
|
46
|
-
outputFiles: {},
|
|
47
|
-
// TODO: add support for critical css inlining.
|
|
48
|
-
inlineCriticalCss: false,
|
|
49
|
-
});
|
|
50
|
-
res.setHeader('Content-Type', 'text/html');
|
|
51
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
52
39
|
(0, utils_1.appendServerConfiguredHeaders)(server, res);
|
|
53
|
-
res.end(
|
|
40
|
+
res.end(content);
|
|
54
41
|
})
|
|
55
42
|
.catch((error) => next(error));
|
|
56
43
|
};
|
|
@@ -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.3';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|
|
@@ -17,7 +17,6 @@ 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
|
-
const RESOLVE_PROTOCOL = 'resolve:';
|
|
21
20
|
function patchFetchToLoadInMemoryAssets() {
|
|
22
21
|
const originalFetch = globalThis.fetch;
|
|
23
22
|
const patchedFetch = async (input, init) => {
|
|
@@ -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 !== 'local-angular-prerender' || !assetFiles[pathname]) {
|
|
40
39
|
// Only handle relative requests or files that are in assets.
|
|
41
40
|
return originalFetch(input, init);
|
|
42
41
|
}
|
|
@@ -5,6 +5,16 @@
|
|
|
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 { ɵServerRenderContext, ɵ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
|
+
ɵServerRenderContext: typeof ɵServerRenderContext;
|
|
16
|
+
ɵextractRoutesAndCreateRouteTree: typeof ɵextractRoutesAndCreateRouteTree;
|
|
17
|
+
ɵgetOrCreateAngularServerApp: typeof ɵgetOrCreateAngularServerApp;
|
|
18
|
+
}
|
|
9
19
|
export declare function loadEsmModuleFromMemory(path: './main.server.mjs'): Promise<MainServerBundleExports>;
|
|
10
|
-
export
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
export declare const SERVER_APP_MANIFEST_FILENAME = "angular-app-manifest.mjs";
|
|
11
|
+
/**
|
|
12
|
+
* Generates the server manifest for the App Engine environment.
|
|
13
|
+
*
|
|
14
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
15
|
+
* Angular application when deployed to Google App Engine. It includes the entry points
|
|
16
|
+
* for different locales and the base HREF for the application.
|
|
17
|
+
*
|
|
18
|
+
* @param i18nOptions - The internationalization options for the application build. This
|
|
19
|
+
* includes settings for inlining locales and determining the output structure.
|
|
20
|
+
* @param baseHref - The base HREF for the application. This is used to set the base URL
|
|
21
|
+
* for all relative URLs in the application.
|
|
22
|
+
* @returns A string representing the content of the SSR server manifest for App Engine.
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], baseHref: string | undefined): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generates the server manifest for the standard Node.js environment.
|
|
27
|
+
*
|
|
28
|
+
* This manifest is used to configure the server-side rendering (SSR) setup for the
|
|
29
|
+
* Angular application when running in a standard Node.js environment. It includes
|
|
30
|
+
* information about the bootstrap module, whether to inline critical CSS, and any
|
|
31
|
+
* additional HTML and CSS output files.
|
|
32
|
+
*
|
|
33
|
+
* @param additionalHtmlOutputFiles - A map of additional HTML output files generated
|
|
34
|
+
* during the build process, keyed by their file paths.
|
|
35
|
+
* @param outputFiles - An array of all output files from the build process, including
|
|
36
|
+
* JavaScript and CSS files.
|
|
37
|
+
* @param inlineCriticalCss - A boolean indicating whether critical CSS should be inlined
|
|
38
|
+
* in the server-side rendered pages.
|
|
39
|
+
* @param routes - An optional array of route definitions for the application, used for
|
|
40
|
+
* server-side rendering and routing.
|
|
41
|
+
* @returns A string representing the content of the SSR server manifest for the Node.js
|
|
42
|
+
* environment.
|
|
43
|
+
*/
|
|
44
|
+
export declare function generateAngularServerAppManifest(additionalHtmlOutputFiles: Map<string, BuildOutputFile>, outputFiles: BuildOutputFile[], inlineCriticalCss: boolean, routes: readonly unknown[] | undefined): string;
|