Skip to content

Commit fb1428a

Browse files
committed
refactor: major clean up of all engines
- add return type to domContentLoadedFactory - remove unused DI tokens - Remove FileLoader implementations from all engines. Instead use the one in @nguniversal/common - Extend RenderOptions Express and Hapi engines interfaces from Common Engine RenderOptions
1 parent 1d38029 commit fb1428a

File tree

22 files changed

+94
-285
lines changed

22 files changed

+94
-285
lines changed

modules/aspnetcore-engine/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ng_module(
1111
module_name = "@nguniversal/aspnetcore-engine",
1212
deps = [
1313
"//modules/aspnetcore-engine/tokens",
14+
"//modules/common/engine",
1415
"@npm//@angular/common",
1516
"@npm//@angular/compiler",
1617
"@npm//@angular/platform-browser",

modules/aspnetcore-engine/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"peerDependencies": {
2626
"@angular/common": "NG_VERSION",
2727
"@angular/core": "NG_VERSION",
28+
"@nguniversal/common": "0.0.0-PLACEHOLDER",
2829
"rxjs": "RXJS_VERSION"
2930
},
3031
"ng-update": {

modules/aspnetcore-engine/src/file-loader.ts

-24
This file was deleted.

modules/aspnetcore-engine/src/main.ts

+28-64
Original file line numberDiff line numberDiff line change
@@ -11,86 +11,58 @@ import { Compiler, CompilerFactory, NgModuleFactory, StaticProvider, Type } from
1111
import { platformDynamicServer } from '@angular/platform-server';
1212

1313
import { ORIGIN_URL, REQUEST } from '@nguniversal/aspnetcore-engine/tokens';
14-
import { FileLoader } from './file-loader';
14+
import { ɵFileLoader } from '@nguniversal/common/engine';
1515
import { IEngineOptions } from './interfaces/engine-options';
1616
import { IEngineRenderResult } from './interfaces/engine-render-result';
1717
import { renderModuleFactory } from './platform-server-utils';
1818

19-
/* @internal */
20-
export class UniversalData {
21-
appNode = '';
22-
title = '';
23-
scripts = '';
24-
styles = '';
25-
meta = '';
26-
links = '';
27-
}
28-
2919
/* @internal */
3020
let appSelector = 'app-root'; // default
3121

3222
/* @internal */
33-
function _getUniversalData(doc: Document): UniversalData {
23+
function _getUniversalData(doc: Document): Omit<IEngineRenderResult, 'moduleRef'> {
3424

35-
const STYLES: string[] = [];
36-
const SCRIPTS: string[] = [];
37-
const META: string[] = [];
38-
const LINKS: string[] = [];
25+
const styles: string[] = [];
26+
const scripts: string[] = [];
27+
const meta: string[] = [];
28+
const links: string[] = [];
3929

40-
// tslint:disable-next-line: no-non-null-assertion
41-
for (let i = 0; i < doc.head!.children.length; i++) {
42-
// tslint:disable-next-line: no-non-null-assertion
43-
const element = doc.head!.children[i];
44-
const tagName = element.tagName.toUpperCase();
45-
46-
switch (tagName) {
47-
case 'SCRIPT':
48-
SCRIPTS.push(element.outerHTML);
49-
break;
50-
case 'STYLE':
51-
STYLES.push(element.outerHTML);
52-
break;
53-
case 'LINK':
54-
LINKS.push(element.outerHTML);
55-
break;
56-
case 'META':
57-
META.push(element.outerHTML);
58-
break;
59-
default:
60-
break;
61-
}
62-
}
63-
64-
for (let i = 0; i < doc.body.children.length; i++) {
65-
const element: Element = doc.body.children[i];
66-
const tagName = element.tagName.toUpperCase();
30+
// tslint:disable: no-non-null-assertion
31+
const elements = [
32+
...Array.from(doc.head!.children),
33+
...Array.from(doc.body!.children),
34+
];
35+
// tslint:enable: no-non-null-assertion
6736

68-
switch (tagName) {
37+
for (const element of elements) {
38+
switch (element.tagName.toUpperCase()) {
6939
case 'SCRIPT':
70-
SCRIPTS.push(element.outerHTML);
40+
scripts.push(element.outerHTML);
7141
break;
7242
case 'STYLE':
73-
STYLES.push(element.outerHTML);
43+
styles.push(element.outerHTML);
7444
break;
7545
case 'LINK':
76-
LINKS.push(element.outerHTML);
46+
links.push(element.outerHTML);
7747
break;
7848
case 'META':
79-
META.push(element.outerHTML);
49+
meta.push(element.outerHTML);
8050
break;
8151
default:
8252
break;
8353
}
8454
}
8555

8656
return {
87-
title: doc.title,
8857
// tslint:disable-next-line: no-non-null-assertion
89-
appNode: doc.querySelector(appSelector)!.outerHTML,
90-
scripts: SCRIPTS.join('\n'),
91-
styles: STYLES.join('\n'),
92-
meta: META.join('\n'),
93-
links: LINKS.join('\n')
58+
html: doc.querySelector(appSelector)!.outerHTML,
59+
globals: {
60+
title: doc.title,
61+
scripts: scripts.join('\n'),
62+
styles: styles.join('\n'),
63+
meta: meta.join('\n'),
64+
links: links.join('\n')
65+
}
9466
};
9567
}
9668

@@ -109,7 +81,7 @@ export async function ngAspnetCoreEngine(options: Readonly<IEngineOptions>)
10981
const compiler: Compiler = compilerFactory.createCompiler([
11082
{
11183
providers: [
112-
{ provide: ResourceLoader, useClass: FileLoader, deps: [] }
84+
{ provide: ResourceLoader, useClass: ɵFileLoader, deps: [] }
11385
]
11486
}
11587
]);
@@ -132,18 +104,10 @@ export async function ngAspnetCoreEngine(options: Readonly<IEngineOptions>)
132104
});
133105

134106
const doc = result.moduleRef.injector.get(DOCUMENT);
135-
const universalData = _getUniversalData(doc);
136107

137108
return {
138-
html: universalData.appNode,
139109
moduleRef: result.moduleRef,
140-
globals: {
141-
styles: universalData.styles,
142-
title: universalData.title,
143-
scripts: universalData.scripts,
144-
meta: universalData.meta,
145-
links: universalData.links
146-
}
110+
..._getUniversalData(doc),
147111
};
148112
}
149113

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ describe('Prerender Builder Utils', () => {
4444
loggerErrorSpy = spyOn(CONTEXT.logger, 'error');
4545
});
4646

47-
it('Should return the union of the routes from routes, routesFile, and the extracted routes without any parameterized routes', async () => {
47+
it('Should return the union of the routes from routes, routesFile, and the extracted routes without any parameterized routes',
48+
async () => {
4849
const options = {
4950
routes: ROUTES,
5051
routesFile: ROUTES_FILE,

modules/common/BUILD.bazel

-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ ng_module(
1111
module_name = "@nguniversal/common",
1212
deps = [
1313
"//modules/common/engine",
14-
"//modules/common/tokens",
1514
"@npm//@angular/common",
1615
"@npm//@angular/core",
1716
"@npm//@angular/platform-browser",
@@ -29,7 +28,6 @@ ng_package(
2928
deps = [
3029
":common",
3130
"//modules/common/engine",
32-
"//modules/common/tokens",
3331
],
3432
)
3533

modules/common/engine/private_api.ts

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

9-
export { FileLoader as ɵFileLoader, CommonEngine as ɵCommonEngine,
10-
RenderOptions as ɵRenderOptions } from './src/index';
9+
export {
10+
FileLoader as ɵFileLoader,
11+
CommonEngine as ɵCommonEngine,
12+
RenderOptions as ɵRenderOptions,
13+
} from './src/index';

modules/common/engine/src/engine.ts

+20-9
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,18 @@
88
import { ResourceLoader } from '@angular/compiler';
99
import { Compiler, CompilerFactory, NgModuleFactory, StaticProvider, Type } from '@angular/core';
1010
import { INITIAL_CONFIG, platformDynamicServer, renderModuleFactory } from '@angular/platform-server';
11-
import * as fs from 'fs';
1211

1312
import { FileLoader } from './file-loader';
14-
import { RenderOptions } from './interfaces';
13+
import { readFile } from './utils';
14+
15+
/** These are the allowed options for the render */
16+
export interface RenderOptions {
17+
bootstrap: Type<{}> | NgModuleFactory<{}>;
18+
providers?: StaticProvider[];
19+
url?: string;
20+
document?: string;
21+
documentFilePath?: string;
22+
}
1523

1624
/**
1725
* A common rendering engine utility. This abstracts the logic
@@ -30,7 +38,7 @@ export class CommonEngine {
3038
}
3139

3240
private factoryCacheMap = new Map<Type<{}>, NgModuleFactory<{}>>();
33-
private templateCache: {[key: string]: string} = {};
41+
private templateCache = new Map<string, string>();
3442

3543
constructor(private moduleOrFactory?: Type<{}> | NgModuleFactory<{}>,
3644
private providers: StaticProvider[] = []) {}
@@ -41,7 +49,7 @@ export class CommonEngine {
4149
*/
4250
async render(opts: RenderOptions): Promise<string> {
4351
// if opts.document dosen't exist then opts.documentFilePath must
44-
const doc = opts.document || await this.getDocument(opts.documentFilePath as string);
52+
const doc = opts.document || opts.documentFilePath && await this.getDocument(opts.documentFilePath);
4553
const extraProviders = [
4654
...(opts.providers || []),
4755
...(this.providers || []),
@@ -83,11 +91,14 @@ export class CommonEngine {
8391
}
8492

8593
/** Retrieve the document from the cache or the filesystem */
86-
private getDocument(filePath: string): Promise<string> {
87-
const doc = this.templateCache[filePath] = this.templateCache[filePath] ||
88-
fs.readFileSync(filePath).toString();
94+
async getDocument(filePath: string): Promise<string> {
95+
let doc = this.templateCache.get(filePath);
96+
97+
if (!doc) {
98+
doc = await readFile(filePath, 'utf-8');
99+
this.templateCache.set(filePath, doc);
100+
}
89101

90-
// As promise so we can change the API later without breaking
91-
return Promise.resolve(doc);
102+
return doc;
92103
}
93104
}

modules/common/engine/src/file-loader.ts

+2-10
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,11 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { ResourceLoader } from '@angular/compiler';
9-
import * as fs from 'fs';
9+
import { readFile } from './utils';
1010

1111
/** ResourceLoader implementation for loading files */
1212
export class FileLoader implements ResourceLoader {
1313
get(url: string): Promise<string> {
14-
return new Promise((resolve, reject) => {
15-
fs.readFile(url, (err: NodeJS.ErrnoException | null, data: Buffer) => {
16-
if (err) {
17-
return reject(err);
18-
}
19-
20-
resolve(data.toString());
21-
});
22-
});
14+
return readFile(url, 'utf-8');
2315
}
2416
}

modules/common/engine/src/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
export * from './interfaces';
98
export * from './file-loader';
109
export * from './engine';

modules/common/engine/src/interfaces.ts

-17
This file was deleted.

modules/common/tokens/public_api.ts renamed to modules/common/engine/src/utils.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
export * from './private_api';
8+
9+
import * as fs from 'fs';
10+
import { promisify } from 'util';
11+
12+
export const readFile = promisify(fs.readFile);

modules/common/src/state-transfer-initializer/module.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,21 @@
99
import { DOCUMENT } from '@angular/common';
1010
import { APP_INITIALIZER, NgModule } from '@angular/core';
1111

12-
export function domContentLoadedFactory(doc: Document) {
12+
13+
export function domContentLoadedFactory(doc: Document): () => Promise<void> {
1314
return () => new Promise ((resolve, _reject) => {
15+
if (doc.readyState === 'complete' || doc.readyState === 'interactive') {
16+
resolve();
17+
18+
return;
19+
}
20+
1421
const contentLoaded = () => {
1522
doc.removeEventListener('DOMContentLoaded', contentLoaded);
1623
resolve();
1724
};
18-
if (doc.readyState === 'complete' || doc.readyState === 'interactive') {
19-
resolve();
20-
} else {
21-
doc.addEventListener('DOMContentLoaded', contentLoaded);
22-
}
25+
26+
doc.addEventListener('DOMContentLoaded', contentLoaded);
2327
});
2428
}
2529

modules/common/tokens/BUILD.bazel

-15
This file was deleted.

modules/common/tokens/index.ts

-8
This file was deleted.

0 commit comments

Comments
 (0)