Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.
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
9 changes: 7 additions & 2 deletions modules/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ ng_module(
"src/**/*.ts",
]),
module_name = "@nguniversal/common",
deps = [],
deps = [
"//modules/common/tokens",
],
)

ng_package(
name = "npm_package",
srcs = [":package.json"],
entry_point = "modules/common/index.js",
readme_md = ":README.md",
deps = [":common"],
deps = [
":common",
"//modules/common/tokens",
],
)

ts_library(
Expand Down
8 changes: 8 additions & 0 deletions modules/common/private_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @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.io/license
*/
export { FileLoader as ɵFileLoader, CommonEngine as ɵCommonEngine } from './src/common-engine';
1 change: 1 addition & 0 deletions modules/common/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
*/
export { TransferHttpCacheModule } from './src/transfer_http';
export { StateTransferInitializerModule } from './src/state-transfer-initializer/module';
export * from './private_api';
92 changes: 92 additions & 0 deletions modules/common/src/common-engine/engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* @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.io/license
*/
import {ResourceLoader} from '@angular/compiler';
import {Compiler, Type, NgModuleFactory, CompilerFactory, StaticProvider} from '@angular/core';
import {INITIAL_CONFIG, renderModuleFactory, platformDynamicServer} from '@angular/platform-server';
import * as fs from 'fs';

import {FileLoader} from './file-loader';
import {RenderOptions} from './interfaces';

/**
* A common rendering engine utility. This abstracts the logic
* for handling the platformServer compiler, the module cache, and
* the document loader
*/
export class CommonEngine {

/** Return an instance of the platformServer compiler */
getCompiler(): Compiler {
const compilerFactory: CompilerFactory = platformDynamicServer().injector.get(CompilerFactory);
return compilerFactory.createCompiler([
{providers: [{provide: ResourceLoader, useClass: FileLoader, deps: []}]}
]);
}

private factoryCacheMap = new Map<Type<{}>, NgModuleFactory<{}>>();
private templateCache: {[key: string]: string} = {};

constructor(private moduleOrFactory: Type<{}> | NgModuleFactory<{}>,
private providers: StaticProvider[] = []) {}

/**
* Render an HTML document for a specific URL with specified
* render options
*/
render(filePath: string, opts: RenderOptions): Promise<string> {
const extraProviders = [
...(opts.providers || []),
...(this.providers || []),
[
{
provide: INITIAL_CONFIG,
useValue: {
document: opts.document || this.getDocument(filePath),
url: opts.url
}
}
]
];

return this.getFactory()
.then(factory => renderModuleFactory(factory, {extraProviders}));
}

/** Return the factory for a given engine instance */
getFactory(): Promise<NgModuleFactory<{}>> {
// If module has been compiled AoT
const moduleOrFactory = this.moduleOrFactory;
if (moduleOrFactory instanceof NgModuleFactory) {
return Promise.resolve(moduleOrFactory);
} else {
// we're in JIT mode
let moduleFactory = this.factoryCacheMap.get(moduleOrFactory);

// If module factory is cached
if (moduleFactory) {
return Promise.resolve(moduleFactory);
}

// Compile the module and cache it
return this.getCompiler().compileModuleAsync(moduleOrFactory)
.then((factory) => {
this.factoryCacheMap.set(moduleOrFactory, factory);
return factory;
});
}
}

/** Retrieve the document from the cache or the filesystem */
private getDocument(filePath: string): Promise<string> {
const doc = this.templateCache[filePath] = this.templateCache[filePath] ||
fs.readFileSync(filePath).toString();

// As promise so we can change the API later without breaking
return Promise.resolve(doc);
}
}
27 changes: 27 additions & 0 deletions modules/common/src/common-engine/file-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @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.io/license
*/
import * as fs from 'fs';
import { ResourceLoader } from '@angular/compiler';

/**
* ResourceLoader implementation for loading files
* @internal
*/
export class FileLoader implements ResourceLoader {
get(url: string): Promise<string> {
return new Promise((resolve, reject) => {
fs.readFile(url, (err: NodeJS.ErrnoException, buffer: Buffer) => {
if (err) {
return reject(err);
}

resolve(buffer.toString());
});
});
}
}
10 changes: 10 additions & 0 deletions modules/common/src/common-engine/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @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.io/license
*/
export * from './interfaces';
export * from './file-loader';
export * from './engine';
22 changes: 22 additions & 0 deletions modules/common/src/common-engine/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @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.io/license
*/
import {NgModuleFactory, StaticProvider, Type} from '@angular/core';

/** These are the allowed options for the engine */
export interface NgSetupOptions {
bootstrap: Type<{}> | NgModuleFactory<{}>;
providers?: StaticProvider[];
}

/** These are the allowed options for the render */
export interface RenderOptions extends NgSetupOptions {
req: any;
res?: any;
document?: string;
url?: string;
}
11 changes: 11 additions & 0 deletions modules/common/tokens/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ng_module")

ng_module(
name = "tokens",
srcs = glob([
"src/*.ts",
]),
module_name = "@nguniversal/common/tokens",
)
8 changes: 8 additions & 0 deletions modules/common/tokens/private_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @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.io/license
*/
export {ORIGIN_URL as ɵORIGIN_URL, REQUEST as ɵREQUEST, RESPONSE as ɵRESPONSE} from './src/tokens';
8 changes: 8 additions & 0 deletions modules/common/tokens/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @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.io/license
*/
export * from './private_api';
12 changes: 12 additions & 0 deletions modules/common/tokens/src/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @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.io/license
*/
import { InjectionToken } from '@angular/core';

export const ORIGIN_URL = new InjectionToken<any>('ORIGIN_URL');
export const REQUEST = new InjectionToken<any>('REQUEST');
export const RESPONSE = new InjectionToken<any>('RESPONSE');