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
2 changes: 1 addition & 1 deletion integration/hapi-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"babel-loader": "^6.4.0",
"babel-preset-es2015": "^6.22.0",
"concurrently": "3.1.0",
"inert": "^4.2.1",
"inert": "^5.1.0",
"protractor": "file:../../node_modules/protractor",
"raw-loader": "^0.5.1",
"webpack": "^2.2.1"
Expand Down
49 changes: 21 additions & 28 deletions integration/hapi-engine/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,48 @@ import {ngHapiEngine} from '@nguniversal/hapi-engine';
require('zone.js/dist/zone-node.js');

import {enableProdMode} from '@angular/core';
import * as Hapi from 'hapi';
import {Server, Request} from 'hapi';
import * as Inert from 'inert';

import {HelloWorldServerModuleNgFactory} from './helloworld/app.server.ngfactory';
import {Base_Reply} from 'hapi';
const helloworld = require('raw-loader!./helloworld/index.html');

const server = new Hapi.Server();
server.connection({ port: 9876, host: 'localhost' });
server.register(Inert, () => {});
const server = new Server({ port: 9876, host: 'localhost' });

enableProdMode();

// Client bundles will be statically served from the built/ directory.
server.route({
method: 'GET',
path: '/built/{file*}',
handler: {
directory: {
path: 'built'
}
}
});

// Keep the browser logs free of errors.
server.route({
method: 'GET',
path: '/favicon.ico',
handler: function (request, reply) {
reply('');
}
handler: () => ''
});

//-----------ADD YOUR SERVER SIDE RENDERED APP HERE ----------------------
server.route({
method: 'GET',
path: '/helloworld',
handler: (req: Request, reply: Base_Reply) => {
handler: (req: Request) =>
ngHapiEngine({
bootstrap: HelloWorldServerModuleNgFactory,
req,
document: helloworld
} as any).then(html => reply(html));
}
})
});

server.start((err) => {
if (err) {
throw err;
}
console.log('Server listening on port 9876!');
});
(async() => {
await server.register(Inert);

// Client bundles will be statically served from the built/ directory.
server.route({
method: 'GET',
path: '/built/{file*}',
handler: {
directory: {
path: 'built'
}
}
});

await server.start();
})();
2 changes: 1 addition & 1 deletion modules/express-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@angular/common": "NG_VERSION",
"@angular/core": "NG_VERSION",
"@angular/platform-server": "NG_VERSION",
"express": "^4.15.2"
"express": "EXPRESS_VERSION"
},
"ng-update": {
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
Expand Down
37 changes: 12 additions & 25 deletions modules/hapi-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This is a Hapi Engine for running Angular Apps on the server for server side ren
To use it, set the engine and then route requests to it

```ts
import { Base_Reply, Request, Server } from 'hapi';
import { Request, Server } from 'hapi';
import { ngHapiEngine } from '@nguniversal/hapi-engine';

const server = new Server();
Expand All @@ -18,20 +18,10 @@ server.connection({
port: 8000
});

// Set the engine
const hapiEngine = ngHapiEngine({
bootstrap: ServerAppModule // Give it a module to bootstrap
});

server.route({
method: 'GET',
path: '/{path*}',
handler: (req: Request, reply: Base_Reply) => {
hapiEngine({
req
}).then(html => reply(html))
.then(err => reply(boom.wrap(err)));
}
handler: (req: Request) => ngHapiEngine({req, bootstrap: ServerAppModule})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it have to instantiate the whole engine per request? feels like a bit of overhead

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, at least for now, because the argument for ngHapiEngine is RenderOptions, which has a mandatory req. And it's not instantiation. Remember: the engine is just a function wrapper around renderPlatformServer. It still does all the caching because that's handled in a constant external to the wrapper.

});
```

Expand All @@ -44,15 +34,14 @@ is called. To do so, simply pass in a `url` and/or `document` string to the rend
server.route({
method: 'GET',
path: '/{path*}',
handler: (req: Request, reply: Base_Reply) => {
let url = 'http://someurl.com';
let doc = '<html><head><title>New doc</title></head></html>';
hapiEngine({
handler: (req: Request) => {
const url = 'http://someurl.com';
const document = '<html><head><title>New doc</title></head></html>';
return ngHapiEngine({
req,
url,
document: doc
}).then(html => reply(html))
.then(err => reply(boom.wrap(err)));
document,
});
}
});
```
Expand Down Expand Up @@ -80,23 +69,21 @@ The Bootstrap module as well as more providers can be passed on request
server.route({
method: 'GET',
path: '/{path*}',
handler: (req: Request, reply: Base_Reply) => {
hapiEngine({
handler: (req: Request) =>
ngHapiEngine({
bootstrap: OtherServerAppModule,
providers: [
OtherServerService
],
req
}).then(html => reply(html))
.then(err => reply(boom.wrap(err)));
}
})
});
```

### Using the Request and Response

The Request and Response objects are injected into the app via injection tokens.
You can access them by @Inject
You can access them by `@Inject`

```ts
import { Request } from 'hapi';
Expand Down
2 changes: 1 addition & 1 deletion modules/hapi-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@angular/common": "NG_VERSION",
"@angular/core": "NG_VERSION",
"@angular/platform-server": "NG_VERSION",
"hapi": "^16.1.1"
"hapi": "HAPI_VERSION"
},
"ng-update": {
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
Expand Down
68 changes: 66 additions & 2 deletions modules/hapi-engine/spec/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
import {Component, destroyPlatform, getPlatform, NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import {ngHapiEngine} from '@nguniversal/hapi-engine';
import {ServerInjectResponse, Request, Server} from 'hapi';
import 'zone.js';
import {BrowserModule} from '@angular/platform-browser';

@Component({selector: 'app', template: `Works!`})
class MyServerApp {
}


@NgModule({
bootstrap: [MyServerApp],
declarations: [MyServerApp],
imports: [ServerModule, BrowserModule.withServerTransition({appId: 'hapi-test'})],
})
class ExampleModule {
}


describe('test runner', () => {
it('can run a test', () => {
expect(true).toBe(true);

const server = new Server({ debug: false });
server.route([
{
method: 'GET',
path: '/',
handler: (req: Request) => ngHapiEngine({
bootstrap: ExampleModule,
req,
document: '<html><body><app></app></body></html>'
})
},
{
method: 'GET',
path: '/test',
handler: () => 'ok'
},
]);

beforeEach(async () => {
if (getPlatform()) {
destroyPlatform();
}
});

it('should test the server', async () => {
const request = {
method: 'GET',
url: '/test'
};

const res = await server.inject(request);
expect(res.result).toBeDefined();
expect(res.result).toBe('ok' as any);
});

it('Returns a reply on successful request', async () => {
const request = {
method: 'GET',
url: '/'
};

const res: ServerInjectResponse = await server.inject(request);
expect(res.result).toBeDefined();
expect(res.result).toContain('Works!');
});
});
20 changes: 5 additions & 15 deletions modules/hapi-engine/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as fs from 'fs';
import { Request, Response } from 'hapi';
import { Request, ResponseToolkit } from 'hapi';

import { NgModuleFactory, Type, CompilerFactory, Compiler, StaticProvider } from '@angular/core';
import { ResourceLoader } from '@angular/compiler';
Expand All @@ -32,7 +32,7 @@ export interface NgSetupOptions {
*/
export interface RenderOptions extends NgSetupOptions {
req: Request;
res?: Response;
res?: ResponseToolkit;
url?: string;
document?: string;
}
Expand Down Expand Up @@ -90,16 +90,8 @@ export function ngHapiEngine(options: RenderOptions) {
]);

getFactory(moduleOrFactory, compiler)
.then(factory => {
return renderModuleFactory(factory, {
extraProviders
});
})
.then((html: string) => {
resolve(html);
}, (err) => {
reject(err);
});
.then(factory => renderModuleFactory(factory, {extraProviders}))
.then(resolve, reject);
});
}

Expand Down Expand Up @@ -128,9 +120,7 @@ function getFactory(
.then((factory) => {
factoryCacheMap.set(moduleOrFactory, factory);
resolve(factory);
}, (err => {
reject(err);
}));
}, reject);
}
});
}
Expand Down
4 changes: 2 additions & 2 deletions modules/hapi-engine/tokens/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* 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 { Request, Response } from 'hapi';
import { Request, ResponseToolkit } from 'hapi';
import { InjectionToken } from '@angular/core';

export const REQUEST = new InjectionToken<Request>('REQUEST');
export const RESPONSE = new InjectionToken<Response>('RESPONSE');
export const RESPONSE = new InjectionToken<ResponseToolkit>('RESPONSE');
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@
"@bazel/ibazel": "^0.3.1",
"@types/express": "^4.0.39",
"@types/fs-extra": "^4.0.5",
"@types/hapi": "^16.1.2",
"@types/hapi": "^17.0.12",
"@types/jasmine": "^2.8.6",
"@types/node": "^9.4.6",
"camelcase": "^4.1.0",
"express": "^4.15.2",
"fs-extra": "^3.0.1",
"glob": "^7.1.2",
"hapi": "^16.1.1",
"hapi": "^17.5.1",
"jasmine-core": "^2.8.0",
"karma": "^2.0.0",
"karma-chrome-launcher": "^2.2.0",
Expand Down
10 changes: 7 additions & 3 deletions tools/defaults.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ DEFAULT_NODE_MODULES = "//:node_modules"

NG_VERSION = "^6.0.0-rc.0"
RXJS_VERSION = "^6.0.0-beta.0"
HAPI_VERSION = "^17.0.0"
EXPRESS_VERSION = "^4.15.2"

NGUNIVERSAL_SCOPED_PACKAGES = ["@nguniversal/%s" % p for p in [
"aspnetcore-engine",
Expand All @@ -20,6 +22,8 @@ NGUNIVERSAL_SCOPED_PACKAGES = ["@nguniversal/%s" % p for p in [
PKG_GROUP_REPLACEMENTS = {
"NG_VERSION": NG_VERSION,
"RXJS_VERSION": RXJS_VERSION,
"HAPI_VERSION": HAPI_VERSION,
"EXPRESS_VERSION": EXPRESS_VERSION,
"\"NG_UPDATE_PACKAGE_GROUP\"": """[
%s
]""" % ",\n ".join(["\"%s\"" % s for s in NGUNIVERSAL_SCOPED_PACKAGES])
Expand All @@ -39,14 +43,14 @@ GLOBALS = {
"@nguniversal/express-engine/tokens": "nguniversal.expressEngine.tokens",
"@nguniversal/hapi-engine/tokens": "nguniversal.hapiEngine.tokens",
'tslib': 'tslib',
"rxjs": "Rx",
"rxjs/operators": "Rx.operators",
"rxjs": "rxjs",
"rxjs/operators": "rxjs.operators",
"fs": "fs",
"express": "express",
"hapi": "hapi"
}

# TODO: when a better api for defaults is avilable use that isntead of these macros
# TODO(Toxicable): when a better api for defaults is avilable use that instead of these macros
def ts_test_library(node_modules=None, **kwargs):
ts_library(testonly=1, **kwargs)

Expand Down
Loading