mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 02:54:21 +08:00
refactor(@angular/ssr): expose private APIs for build system integration and refactor app management
- Exposed several utility functions as private APIs to support the integration with the build system. - Removed `isDevMode` and caching logic from `AngularAppEngine`. This was necessary to better handle updates when using Vite. Instead, `AngularServerApp` is now treated as a singleton to simplify management. - Switched asset storage from an `Object` to a `Map` in the manifest for improved efficiency and consistency. This refactor sets the groundwork for seamless wiring with the build system.
This commit is contained in:
parent
d6155d2761
commit
1c185183c3
18
packages/angular/ssr/private_export.ts
Normal file
18
packages/angular/ssr/private_export.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
export { ServerRenderContext as ɵServerRenderContext } from './src/render';
|
||||
export { getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig } from './src/routes/ng-routes';
|
||||
export {
|
||||
getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp,
|
||||
destroyAngularServerApp as ɵdestroyAngularServerApp,
|
||||
} from './src/app';
|
||||
export {
|
||||
setAngularAppManifest as ɵsetAngularAppManifest,
|
||||
setAngularAppEngineManifest as ɵsetAngularAppEngineManifest,
|
||||
} from './src/manifest';
|
@ -12,4 +12,4 @@ export {
|
||||
type CommonEngineOptions,
|
||||
} from './src/common-engine/common-engine';
|
||||
|
||||
export { getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig } from './src/routes/ng-routes';
|
||||
export * from './private_export';
|
||||
|
@ -6,10 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import { AngularServerApp } from './app';
|
||||
import { Hooks } from './hooks';
|
||||
import { getPotentialLocaleIdFromUrl } from './i18n';
|
||||
import { getAngularAppEngineManifest } from './manifest';
|
||||
import { EntryPointExports, getAngularAppEngineManifest } from './manifest';
|
||||
|
||||
/**
|
||||
* Angular server application engine.
|
||||
@ -19,43 +18,33 @@ import { getAngularAppEngineManifest } from './manifest';
|
||||
export class AngularAppEngine {
|
||||
/**
|
||||
* Hooks for extending or modifying the behavior of the server application.
|
||||
* @internal This property is accessed by the Angular CLI when running the dev-server.
|
||||
* These hooks are used by the Angular CLI when running the development server and
|
||||
* provide extensibility points for the application lifecycle.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
static hooks = new Hooks();
|
||||
|
||||
/**
|
||||
* Hooks for extending or modifying the behavior of the server application.
|
||||
* This instance can be used to attach custom functionality to various events in the server application lifecycle.
|
||||
* Provides access to the hooks for extending or modifying the server application's behavior.
|
||||
* This allows attaching custom functionality to various server application lifecycle events.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
get hooks(): Hooks {
|
||||
return AngularAppEngine.hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the application is operating in development mode.
|
||||
* This property controls the activation of features intended for production, such as caching mechanisms.
|
||||
* @internal
|
||||
*/
|
||||
static isDevMode = false;
|
||||
|
||||
/**
|
||||
* The manifest for the server application.
|
||||
*/
|
||||
private readonly manifest = getAngularAppEngineManifest();
|
||||
|
||||
/**
|
||||
* Map of locale strings to corresponding `AngularServerApp` instances.
|
||||
* Each instance represents an Angular server application.
|
||||
*/
|
||||
private readonly appsCache = new Map<string, AngularServerApp>();
|
||||
|
||||
/**
|
||||
* Renders an HTTP request using the appropriate Angular server application and returns a response.
|
||||
* Renders a response for the given HTTP request using the server application.
|
||||
*
|
||||
* This method determines the entry point for the Angular server application based on the request URL,
|
||||
* and caches the server application instances for reuse. If the application is in development mode,
|
||||
* the cache is bypassed and a new instance is created for each request.
|
||||
* This method processes the request, determines the appropriate route and rendering context,
|
||||
* and returns an HTTP response.
|
||||
*
|
||||
* If the request URL appears to be for a file (excluding `/index.html`), the method returns `null`.
|
||||
* A request to `https://www.example.com/page/index.html` will render the Angular route
|
||||
@ -69,25 +58,14 @@ export class AngularAppEngine {
|
||||
async render(request: Request, requestContext?: unknown): Promise<Response | null> {
|
||||
// Skip if the request looks like a file but not `/index.html`.
|
||||
const url = new URL(request.url);
|
||||
|
||||
const entryPoint = this.getEntryPointFromUrl(url);
|
||||
if (!entryPoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [locale, loadModule] = entryPoint;
|
||||
let serverApp = this.appsCache.get(locale);
|
||||
if (!serverApp) {
|
||||
const { AngularServerApp } = await loadModule();
|
||||
serverApp = new AngularServerApp({
|
||||
isDevMode: AngularAppEngine.isDevMode,
|
||||
hooks: this.hooks,
|
||||
});
|
||||
|
||||
if (!AngularAppEngine.isDevMode) {
|
||||
this.appsCache.set(locale, serverApp);
|
||||
}
|
||||
}
|
||||
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = await entryPoint();
|
||||
const serverApp = getOrCreateAngularServerApp();
|
||||
serverApp.hooks = this.hooks;
|
||||
|
||||
return serverApp.render(request, requestContext);
|
||||
}
|
||||
@ -99,30 +77,18 @@ export class AngularAppEngine {
|
||||
* If there is only one entry point available, it is returned regardless of the URL.
|
||||
* Otherwise, the method extracts a potential locale identifier from the URL and looks up the corresponding entry point.
|
||||
*
|
||||
* @param url - The URL used to derive the locale and determine the entry point.
|
||||
* @returns An array containing:
|
||||
* - The first element is the locale extracted from the URL.
|
||||
* - The second element is a function that returns a promise resolving to an object with the `AngularServerApp` type.
|
||||
*
|
||||
* Returns `null` if no matching entry point is found for the extracted locale.
|
||||
* @param url - The URL used to derive the locale and determine the appropriate entry point.
|
||||
* @returns A function that returns a promise resolving to an object with the `EntryPointExports` type,
|
||||
* or `undefined` if no matching entry point is found for the extracted locale.
|
||||
*/
|
||||
private getEntryPointFromUrl(url: URL):
|
||||
| [
|
||||
locale: string,
|
||||
loadModule: () => Promise<{
|
||||
AngularServerApp: typeof AngularServerApp;
|
||||
}>,
|
||||
]
|
||||
| null {
|
||||
// Find bundle for locale
|
||||
private getEntryPointFromUrl(url: URL): (() => Promise<EntryPointExports>) | undefined {
|
||||
const { entryPoints, basePath } = this.manifest;
|
||||
if (entryPoints.size === 1) {
|
||||
return entryPoints.entries().next().value;
|
||||
return entryPoints.values().next().value;
|
||||
}
|
||||
|
||||
const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath);
|
||||
const entryPoint = entryPoints.get(potentialLocale);
|
||||
|
||||
return entryPoint ? [potentialLocale, entryPoint] : null;
|
||||
return entryPoints.get(potentialLocale);
|
||||
}
|
||||
}
|
||||
|
@ -12,49 +12,24 @@ import { getAngularAppManifest } from './manifest';
|
||||
import { ServerRenderContext, render } from './render';
|
||||
import { ServerRouter } from './routes/router';
|
||||
|
||||
/**
|
||||
* Configuration options for initializing a `AngularServerApp` instance.
|
||||
*/
|
||||
export interface AngularServerAppOptions {
|
||||
/**
|
||||
* Indicates whether the application is in development mode.
|
||||
*
|
||||
* When set to `true`, the application runs in development mode with additional debugging features.
|
||||
*/
|
||||
isDevMode?: boolean;
|
||||
|
||||
/**
|
||||
* Optional hooks for customizing the server application's behavior.
|
||||
*/
|
||||
hooks?: Hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a locale-specific Angular server application managed by the server application engine.
|
||||
*
|
||||
* The `AngularServerApp` class handles server-side rendering and asset management for a specific locale.
|
||||
*/
|
||||
export class AngularServerApp {
|
||||
/**
|
||||
* Hooks for extending or modifying the behavior of the server application.
|
||||
* This instance can be used to attach custom functionality to various events in the server application lifecycle.
|
||||
*/
|
||||
hooks = new Hooks();
|
||||
|
||||
/**
|
||||
* The manifest associated with this server application.
|
||||
* @internal
|
||||
*/
|
||||
readonly manifest = getAngularAppManifest();
|
||||
|
||||
/**
|
||||
* Hooks for extending or modifying the behavior of the server application.
|
||||
* This instance can be used to attach custom functionality to various events in the server application lifecycle.
|
||||
* @internal
|
||||
*/
|
||||
readonly hooks: Hooks;
|
||||
|
||||
/**
|
||||
* Specifies if the server application is operating in development mode.
|
||||
* This property controls the activation of features intended for production, such as caching mechanisms.
|
||||
* @internal
|
||||
*/
|
||||
readonly isDevMode: boolean;
|
||||
|
||||
/**
|
||||
* An instance of ServerAsset that handles server-side asset.
|
||||
* @internal
|
||||
@ -66,18 +41,6 @@ export class AngularServerApp {
|
||||
*/
|
||||
private router: ServerRouter | undefined;
|
||||
|
||||
/**
|
||||
* Creates a new `AngularServerApp` instance with the provided configuration options.
|
||||
*
|
||||
* @param options - The configuration options for the server application.
|
||||
* - `isDevMode`: Flag indicating if the application is in development mode.
|
||||
* - `hooks`: Optional hooks for customizing application behavior.
|
||||
*/
|
||||
constructor(readonly options: AngularServerAppOptions) {
|
||||
this.isDevMode = options.isDevMode ?? false;
|
||||
this.hooks = options.hooks ?? new Hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a response for the given HTTP request using the server application.
|
||||
*
|
||||
@ -113,3 +76,34 @@ export class AngularServerApp {
|
||||
return render(this, request, serverContext, requestContext);
|
||||
}
|
||||
}
|
||||
|
||||
let angularServerApp: AngularServerApp | undefined;
|
||||
|
||||
/**
|
||||
* Retrieves or creates an instance of `AngularServerApp`.
|
||||
* - If an instance of `AngularServerApp` already exists, it will return the existing one.
|
||||
* - If no instance exists, it will create a new one with the provided options.
|
||||
* @returns The existing or newly created instance of `AngularServerApp`.
|
||||
*/
|
||||
export function getOrCreateAngularServerApp(): AngularServerApp {
|
||||
return (angularServerApp ??= new AngularServerApp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the instance of `AngularServerApp` to undefined, effectively
|
||||
* clearing the reference. Use this to recreate the instance.
|
||||
*/
|
||||
export function resetAngularServerApp(): void {
|
||||
angularServerApp = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the existing `AngularServerApp` instance, releasing associated resources and resetting the
|
||||
* reference to `undefined`.
|
||||
*
|
||||
* This function is primarily used to enable the recreation of the `AngularServerApp` instance,
|
||||
* typically when server configuration or application state needs to be refreshed.
|
||||
*/
|
||||
export function destroyAngularServerApp(): void {
|
||||
angularServerApp = undefined;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export class ServerAssets {
|
||||
* @throws Error If the asset path is not found in the manifest, an error is thrown.
|
||||
*/
|
||||
async getServerAsset(path: string): Promise<string> {
|
||||
const asset = this.manifest.assets[path];
|
||||
const asset = this.manifest.assets.get(path);
|
||||
if (!asset) {
|
||||
throw new Error(`Server asset '${path}' does not exist.`);
|
||||
}
|
||||
|
9
packages/angular/ssr/src/global.d.ts
vendored
Normal file
9
packages/angular/ssr/src/global.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
declare const ngDevMode: boolean | undefined;
|
@ -6,10 +6,25 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import type { AngularServerApp } from './app';
|
||||
import type { destroyAngularServerApp, getOrCreateAngularServerApp } from './app';
|
||||
import type { SerializableRouteTreeNode } from './routes/route-tree';
|
||||
import { AngularBootstrap } from './utils/ng';
|
||||
|
||||
/**
|
||||
* Represents the exports of an Angular server application entry point.
|
||||
*/
|
||||
export interface EntryPointExports {
|
||||
/**
|
||||
* A reference to the function that creates an Angular server application instance.
|
||||
*/
|
||||
ɵgetOrCreateAngularServerApp: typeof getOrCreateAngularServerApp;
|
||||
|
||||
/**
|
||||
* A reference to the function that destroys the `AngularServerApp` instance.
|
||||
*/
|
||||
ɵdestroyAngularServerApp: typeof destroyAngularServerApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manifest for the Angular server application engine, defining entry points.
|
||||
*/
|
||||
@ -18,11 +33,9 @@ export interface AngularAppEngineManifest {
|
||||
* A map of entry points for the server application.
|
||||
* Each entry in the map consists of:
|
||||
* - `key`: The base href for the entry point.
|
||||
* - `value`: A function that returns a promise resolving to an object containing the `AngularServerApp` type.
|
||||
* - `value`: A function that returns a promise resolving to an object of type `EntryPointExports`.
|
||||
*/
|
||||
readonly entryPoints: Readonly<
|
||||
Map<string, () => Promise<{ AngularServerApp: typeof AngularServerApp }>>
|
||||
>;
|
||||
readonly entryPoints: Readonly<Map<string, () => Promise<EntryPointExports>>>;
|
||||
|
||||
/**
|
||||
* The base path for the server application.
|
||||
@ -36,12 +49,12 @@ export interface AngularAppEngineManifest {
|
||||
*/
|
||||
export interface AngularAppManifest {
|
||||
/**
|
||||
* A record of assets required by the server application.
|
||||
* Each entry in the record consists of:
|
||||
* A map of assets required by the server application.
|
||||
* Each entry in the map consists of:
|
||||
* - `key`: The path of the asset.
|
||||
* - `value`: A function returning a promise that resolves to the file contents of the asset.
|
||||
*/
|
||||
readonly assets: Readonly<Record<string, () => Promise<string>>>;
|
||||
readonly assets: Readonly<Map<string, () => Promise<string>>>;
|
||||
|
||||
/**
|
||||
* The bootstrap mechanism for the server application.
|
||||
|
@ -64,25 +64,25 @@ export async function render(
|
||||
);
|
||||
}
|
||||
|
||||
const { manifest, hooks, isDevMode } = app;
|
||||
|
||||
if (isDevMode) {
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed in development.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
|
||||
// An Angular Console Provider that does not print a set of predefined logs.
|
||||
platformProviders.push({
|
||||
provide: ɵConsole,
|
||||
// Using `useClass` would necessitate decorating `Console` with `@Injectable`,
|
||||
// which would require switching from `ts_library` to `ng_module`. This change
|
||||
// would also necessitate various patches of `@angular/bazel` to support ESM.
|
||||
useFactory: () => new Console(),
|
||||
});
|
||||
}
|
||||
|
||||
let html = await app.assets.getIndexServerHtml();
|
||||
// An Angular Console Provider that does not print a set of predefined logs.
|
||||
platformProviders.push({
|
||||
provide: ɵConsole,
|
||||
// Using `useClass` would necessitate decorating `Console` with `@Injectable`,
|
||||
// which would require switching from `ts_library` to `ng_module`. This change
|
||||
// would also necessitate various patches of `@angular/bazel` to support ESM.
|
||||
useFactory: () => new Console(),
|
||||
});
|
||||
|
||||
const { manifest, hooks, assets } = app;
|
||||
|
||||
let html = await assets.getIndexServerHtml();
|
||||
// Skip extra microtask if there are no pre hooks.
|
||||
if (hooks.has('html:transform:pre')) {
|
||||
html = await hooks.run('html:transform:pre', { html });
|
||||
|
@ -188,10 +188,12 @@ export async function getRoutesFromAngularRouterConfig(
|
||||
document: string,
|
||||
url: URL,
|
||||
): Promise<AngularRouterConfigResult> {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed in development.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed in development.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
}
|
||||
|
||||
const { protocol, host } = url;
|
||||
|
||||
|
@ -11,8 +11,8 @@ import 'zone.js/node';
|
||||
import '@angular/compiler';
|
||||
/* eslint-enable import/no-unassigned-import */
|
||||
|
||||
import { Component, ɵresetCompiledComponents } from '@angular/core';
|
||||
import { AngularServerApp } from '../src/app';
|
||||
import { Component } from '@angular/core';
|
||||
import { destroyAngularServerApp, getOrCreateAngularServerApp } from '../src/app';
|
||||
import { AngularAppEngine } from '../src/app-engine';
|
||||
import { setAngularAppEngineManifest } from '../src/manifest';
|
||||
import { setAngularAppTestingManifest } from './testing-utils';
|
||||
@ -21,14 +21,9 @@ describe('AngularAppEngine', () => {
|
||||
let appEngine: AngularAppEngine;
|
||||
|
||||
describe('Localized app', () => {
|
||||
beforeEach(() => {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
destroyAngularServerApp();
|
||||
|
||||
setAngularAppEngineManifest({
|
||||
// Note: Although we are testing only one locale, we need to configure two or more
|
||||
// to ensure that we test a different code path.
|
||||
@ -45,7 +40,10 @@ describe('AngularAppEngine', () => {
|
||||
|
||||
setAngularAppTestingManifest([{ path: 'home', component: HomeComponent }], locale);
|
||||
|
||||
return { AngularServerApp };
|
||||
return {
|
||||
ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp,
|
||||
ɵdestroyAngularServerApp: destroyAngularServerApp,
|
||||
};
|
||||
},
|
||||
]),
|
||||
),
|
||||
@ -93,14 +91,9 @@ describe('AngularAppEngine', () => {
|
||||
});
|
||||
|
||||
describe('Non-localized app', () => {
|
||||
beforeEach(() => {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
destroyAngularServerApp();
|
||||
|
||||
setAngularAppEngineManifest({
|
||||
entryPoints: new Map([
|
||||
[
|
||||
@ -115,7 +108,10 @@ describe('AngularAppEngine', () => {
|
||||
|
||||
setAngularAppTestingManifest([{ path: 'home', component: HomeComponent }]);
|
||||
|
||||
return { AngularServerApp };
|
||||
return {
|
||||
ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp,
|
||||
ɵdestroyAngularServerApp: destroyAngularServerApp,
|
||||
};
|
||||
},
|
||||
],
|
||||
]),
|
||||
|
@ -11,22 +11,17 @@ import 'zone.js/node';
|
||||
import '@angular/compiler';
|
||||
/* eslint-enable import/no-unassigned-import */
|
||||
|
||||
import { Component, ɵresetCompiledComponents } from '@angular/core';
|
||||
import { AngularServerApp } from '../src/app';
|
||||
import { Component } from '@angular/core';
|
||||
import { AngularServerApp, destroyAngularServerApp } from '../src/app';
|
||||
import { ServerRenderContext } from '../src/render';
|
||||
import { setAngularAppTestingManifest } from './testing-utils';
|
||||
|
||||
describe('AngularServerApp', () => {
|
||||
let app: AngularServerApp;
|
||||
|
||||
beforeEach(() => {
|
||||
// Need to clean up GENERATED_COMP_IDS map in `@angular/core`.
|
||||
// Otherwise an incorrect component ID generation collision detected warning will be displayed.
|
||||
// See: https://github.com/angular/angular-cli/issues/25924
|
||||
ɵresetCompiledComponents();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
destroyAngularServerApp();
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-home',
|
||||
@ -41,9 +36,7 @@ describe('AngularServerApp', () => {
|
||||
{ path: 'redirect/absolute', redirectTo: '/home' },
|
||||
]);
|
||||
|
||||
app = new AngularServerApp({
|
||||
isDevMode: true,
|
||||
});
|
||||
app = new AngularServerApp();
|
||||
});
|
||||
|
||||
describe('render', () => {
|
||||
@ -83,7 +76,7 @@ describe('AngularServerApp', () => {
|
||||
expect(response?.status).toBe(302);
|
||||
});
|
||||
|
||||
it('should correctly handle absoloute nested redirects', async () => {
|
||||
it('should correctly handle absolute nested redirects', async () => {
|
||||
const response = await app.render(new Request('http://localhost/redirect/absolute'));
|
||||
expect(response?.headers.get('location')).toContain('http://localhost/home');
|
||||
expect(response?.status).toBe(302);
|
||||
|
@ -15,10 +15,12 @@ describe('ServerAsset', () => {
|
||||
beforeAll(() => {
|
||||
assetManager = new ServerAssets({
|
||||
bootstrap: undefined as never,
|
||||
assets: {
|
||||
'index.server.html': async () => '<html>Index</html>',
|
||||
'index.other.html': async () => '<html>Other</html>',
|
||||
},
|
||||
assets: new Map(
|
||||
Object.entries({
|
||||
'index.server.html': async () => '<html>Index</html>',
|
||||
'index.other.html': async () => '<html>Other</html>',
|
||||
}),
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -24,9 +24,10 @@ import { setAngularAppManifest } from '../src/manifest';
|
||||
export function setAngularAppTestingManifest(routes: Routes, baseHref = ''): void {
|
||||
setAngularAppManifest({
|
||||
inlineCriticalCss: false,
|
||||
assets: {
|
||||
'index.server.html': async () =>
|
||||
`
|
||||
assets: new Map(
|
||||
Object.entries({
|
||||
'index.server.html': async () =>
|
||||
`
|
||||
<html>
|
||||
<head>
|
||||
<base href="/${baseHref}" />
|
||||
@ -35,7 +36,8 @@ export function setAngularAppTestingManifest(routes: Routes, baseHref = ''): voi
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>`,
|
||||
},
|
||||
}),
|
||||
),
|
||||
bootstrap: () => () => {
|
||||
@Component({
|
||||
standalone: true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user