Skip to content

Commit fef00f9

Browse files
committed
feat(@nguniversal/builders): add ng-server-context for SSG pages
This provides an easy way to distinguish between SSR, SSG, and client-side apps (CSR). Closes angular#2612
1 parent a62d3d3 commit fef00f9

File tree

5 files changed

+32
-18
lines changed

5 files changed

+32
-18
lines changed

integration/express-engine-ivy-hybrid/e2e/src/util.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ export async function waitForAppRootElement(): Promise<boolean> {
2020

2121
export async function isPrerendered(): Promise<boolean> {
2222
const src = await browser.driver.getPageSource();
23-
return src.includes('This page was prerendered with Angular Universal');
23+
return src.includes('ng-server-context="ssg"');
2424
}

modules/builders/BUILD.bazel

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ ts_library(
2828
"@npm//@angular-devkit/architect",
2929
"@npm//@angular-devkit/build-angular",
3030
"@npm//@angular-devkit/core",
31+
"@npm//@angular/core",
32+
"@npm//@angular/platform-server",
3133
"@npm//@types/browser-sync",
3234
"@npm//@types/express",
3335
"@npm//guess-parser",

modules/builders/src/prerender/index.spec.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('Prerender Builder', () => {
5757
);
5858

5959
expect(content).toContain('foo works!');
60-
expect(content).toContain('This page was prerendered with Angular Universal');
60+
expect(content).toContain('ng-server-context="ssg"');
6161
await run.stop();
6262
});
6363

@@ -109,13 +109,13 @@ describe('Prerender Builder', () => {
109109
);
110110

111111
expect(appContent).toContain('app app is running!');
112-
expect(appContent).toContain('This page was prerendered with Angular Universal');
112+
expect(appContent).toContain('ng-server-context="ssg"');
113113

114114
expect(fooContent).toContain('foo works!');
115-
expect(fooContent).toContain('This page was prerendered with Angular Universal');
115+
expect(fooContent).toContain('ng-server-context="ssg"');
116116

117117
expect(fooBarContent).toContain('foo-bar works!');
118-
expect(fooBarContent).toContain('This page was prerendered with Angular Universal');
118+
expect(fooBarContent).toContain('ng-server-context="ssg"');
119119

120120
await run.stop();
121121
});
@@ -151,13 +151,13 @@ describe('Prerender Builder', () => {
151151
expect(output.success).toBe(true);
152152

153153
expect(appContent).toContain('app app is running!');
154-
expect(appContent).toContain('This page was prerendered with Angular Universal');
154+
expect(appContent).toContain('ng-server-context="ssg"');
155155

156156
expect(fooContent).toContain('foo works!');
157-
expect(fooContent).toContain('This page was prerendered with Angular Universal');
157+
expect(fooContent).toContain('ng-server-context="ssg"');
158158

159159
expect(fooBarContent).toContain('foo-bar works!');
160-
expect(fooBarContent).toContain('This page was prerendered with Angular Universal');
160+
expect(fooBarContent).toContain('ng-server-context="ssg"');
161161

162162
await run.stop();
163163
});

modules/builders/src/prerender/worker.ts

+22-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import type { Type } from '@angular/core';
10+
import type * as platformServer from '@angular/platform-server';
11+
import assert from 'assert';
912
import * as fs from 'fs';
1013
import * as path from 'path';
1114
import { loadEsmModule } from '../utils/utils';
@@ -41,28 +44,39 @@ export async function render({
4144
const outputFolderPath = path.join(outputPath, route);
4245
const outputIndexPath = path.join(outputFolderPath, 'index.html');
4346

44-
const { renderModule, AppServerModule } = await import(serverBundlePath);
47+
const { AppServerModule, renderModule, ɵSERVER_CONTEXT } = (await import(serverBundlePath)) as {
48+
renderModule: typeof platformServer.renderModule | undefined;
49+
ɵSERVER_CONTEXT: typeof platformServer.ɵSERVER_CONTEXT | undefined;
50+
AppServerModule: Type<unknown> | undefined;
51+
};
52+
53+
assert(renderModule, `renderModule was not exported from: ${serverBundlePath}.`);
54+
assert(AppServerModule, `AppServerModule was not exported from: ${serverBundlePath}.`);
55+
assert(ɵSERVER_CONTEXT, `ɵSERVER_CONTEXT was not exported from: ${serverBundlePath}.`);
4556

4657
const indexBaseName = fs.existsSync(path.join(outputPath, 'index.original.html'))
4758
? 'index.original.html'
4859
: indexFile;
4960
const browserIndexInputPath = path.join(outputPath, indexBaseName);
50-
let indexHtml = await fs.promises.readFile(browserIndexInputPath, 'utf8');
51-
indexHtml = indexHtml.replace(
52-
'</html>',
53-
'<!-- This page was prerendered with Angular Universal -->\n</html>',
54-
);
61+
let document = await fs.promises.readFile(browserIndexInputPath, 'utf8');
62+
5563
if (inlineCriticalCss) {
5664
// Workaround for https://github.com/GoogleChromeLabs/critters/issues/64
57-
indexHtml = indexHtml.replace(
65+
document = document.replace(
5866
/ media="print" onload="this\.media='all'"><noscript><link .+?><\/noscript>/g,
5967
'>',
6068
);
6169
}
6270

6371
let html = await renderModule(AppServerModule, {
64-
document: indexHtml,
72+
document,
6573
url: route,
74+
extraProviders: [
75+
{
76+
provide: ɵSERVER_CONTEXT,
77+
useValue: 'ssg',
78+
},
79+
],
6680
});
6781

6882
if (inlineCriticalCss) {
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { enableProdMode } from '@angular/core';
2-
32
import { environment } from './environments/environment';
43

54
if (environment.production) {
65
enableProdMode();
76
}
87

98
export { AppServerModule } from './app/app.server.module';
10-
export { renderModule } from '@angular/platform-server';

0 commit comments

Comments
 (0)