Skip to content

fix(@angular/ssr): resolve circular dependency issue from main.server.js reference in manifest #28359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions packages/angular/build/src/utils/server-rendering/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,15 @@ export function generateAngularServerAppManifest(
if (
file.path === INDEX_HTML_SERVER ||
file.path === INDEX_HTML_CSR ||
file.path.endsWith('.css')
(inlineCriticalCss && file.path.endsWith('.css'))
) {
serverAssetsContent.push(`['${file.path}', async () => ${JSON.stringify(file.text)}]`);
}
}

const manifestContent = `
import bootstrap from './main.server.mjs';

export default {
bootstrap: () => bootstrap,
bootstrap: () => import('./main.server.mjs').then(m => m.default),
inlineCriticalCss: ${inlineCriticalCss},
routes: ${JSON.stringify(routes, undefined, 2)},
assets: new Map([${serverAssetsContent.join(', \n')}]),
Expand Down
11 changes: 9 additions & 2 deletions packages/angular/ssr/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getAngularAppManifest } from './manifest';
import { ServerRouter } from './routes/router';
import { REQUEST, REQUEST_CONTEXT, RESPONSE_INIT } from './tokens';
import { InlineCriticalCssProcessor } from './utils/inline-critical-css';
import { renderAngular } from './utils/ng';
import { AngularBootstrap, renderAngular } from './utils/ng';

/**
* Enum representing the different contexts in which server rendering can occur.
Expand Down Expand Up @@ -58,6 +58,11 @@ export class AngularServerApp {
*/
private inlineCriticalCssProcessor: InlineCriticalCssProcessor | undefined;

/**
* The bootstrap mechanism for the server application.
*/
private boostrap: AngularBootstrap | undefined;

/**
* Renders a response for the given HTTP request using the server application.
*
Expand Down Expand Up @@ -176,7 +181,9 @@ export class AngularServerApp {
html = await hooks.run('html:transform:pre', { html });
}

html = await renderAngular(html, manifest.bootstrap(), new URL(request.url), platformProviders);
this.boostrap ??= await manifest.bootstrap();

html = await renderAngular(html, this.boostrap, new URL(request.url), platformProviders);

if (manifest.inlineCriticalCss) {
// Optionally inline critical CSS.
Expand Down
5 changes: 3 additions & 2 deletions packages/angular/ssr/src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ export interface AngularAppManifest {

/**
* The bootstrap mechanism for the server application.
* A function that returns a reference to an NgModule or a function returning a promise that resolves to an ApplicationRef.
* A function that returns a promise that resolves to an `NgModule` or a function
* returning a promise that resolves to an `ApplicationRef`.
*/
readonly bootstrap: () => AngularBootstrap;
readonly bootstrap: () => Promise<AngularBootstrap>;

/**
* Indicates whether critical CSS should be inlined into the HTML.
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/ssr/src/routes/ng-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export async function extractRoutesAndCreateRouteTree(
const routeTree = new RouteTree();
const document = await new ServerAssets(manifest).getIndexServerHtml();
const { baseHref, routes } = await getRoutesFromAngularRouterConfig(
manifest.bootstrap(),
await manifest.bootstrap(),
document,
url,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/ssr/test/testing-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function setAngularAppTestingManifest(routes: Routes, baseHref = ''): voi
</html>`,
}),
),
bootstrap: () => () => {
bootstrap: async () => () => {
@Component({
standalone: true,
selector: 'app-root',
Expand Down
29 changes: 17 additions & 12 deletions tests/legacy-cli/e2e/tests/build/ssr/express-engine-csp-nonce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,25 +136,30 @@ export default async function () {
`,
});

async function ngDevSsr(): Promise<number> {
async function spawnServer(): Promise<number> {
const port = await findFreePort();
const useWebpackBuilder = !getGlobalVariable('argv')['esbuild'];
const validBundleRegEx = useWebpackBuilder ? /Compiled successfully\./ : /complete\./;

const runCommand = useWebpackBuilder ? 'serve:ssr' : 'serve:ssr:test-project';

await execAndWaitForOutputToMatch(
'ng',
[
'run',
`test-project:${useWebpackBuilder ? 'serve-ssr' : 'serve'}:production`,
'--port',
String(port),
],
validBundleRegEx,
'npm',
['run', runCommand],
/Node Express server listening on/,
{
'PORT': String(port),
},
);

return port;
}

const port = await ngDevSsr();
await ng('build');

if (useWebpackBuilder) {
// Build server code
await ng('run', 'test-project:server');
}

const port = await spawnServer();
await ng('e2e', `--base-url=http://localhost:${port}`, '--dev-server-target=');
}
30 changes: 18 additions & 12 deletions tests/legacy-cli/e2e/tests/build/ssr/express-engine-ngmodule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,34 @@ export default async function () {
`,
});

async function ngDevSsr(): Promise<number> {
async function spawnServer(): Promise<number> {
const port = await findFreePort();
const validBundleRegEx = useWebpackBuilder ? /Compiled successfully\./ : /complete\./;

const runCommand = useWebpackBuilder ? 'serve:ssr' : `serve:ssr:test-project-two`;

await execAndWaitForOutputToMatch(
'ng',
[
'run',
`test-project-two:${useWebpackBuilder ? 'serve-ssr' : 'serve'}:production`,
'--port',
String(port),
],
validBundleRegEx,
'npm',
['run', runCommand],
/Node Express server listening on/,
{
'PORT': String(port),
},
);

return port;
}

const port = await ngDevSsr();
await ng('build', 'test-project-two');

if (useWebpackBuilder) {
// Build server code
await ng('run', `test-project-two:server`);
}

const port = await spawnServer();
await ng(
'e2e',
'test-project-two',
'--project=test-project-two',
`--base-url=http://localhost:${port}`,
'--dev-server-target=',
);
Expand Down
26 changes: 15 additions & 11 deletions tests/legacy-cli/e2e/tests/build/ssr/express-engine-standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,28 @@ export default async function () {
`,
});

async function ngDevSsr(): Promise<number> {
async function spawnServer(): Promise<number> {
const port = await findFreePort();
const validBundleRegEx = useWebpackBuilder ? /Compiled successfully\./ : /complete\./;
const runCommand = useWebpackBuilder ? 'serve:ssr' : 'serve:ssr:test-project';

await execAndWaitForOutputToMatch(
'ng',
[
'run',
`test-project:${useWebpackBuilder ? 'serve-ssr' : 'serve'}:production`,
'--port',
String(port),
],
validBundleRegEx,
'npm',
['run', runCommand],
/Node Express server listening on/,
{
'PORT': String(port),
},
);

return port;
}

const port = await ngDevSsr();
await ng('build');
if (useWebpackBuilder) {
// Build server code
await ng('run', `test-project:server`);
}

const port = await spawnServer();
await ng('e2e', `--base-url=http://localhost:${port}`, '--dev-server-target=');
}