Skip to content

Commit

Permalink
Angular Universal Example
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherthielen committed Oct 21, 2017
1 parent abe0db2 commit b642962
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 153 deletions.
28 changes: 27 additions & 1 deletion angular-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"apps": [
{
"root": "src",
"outDir": "dist",
"outDir": "dist/browser",
"assets": [
"assets",
"favicon.ico"
Expand All @@ -28,7 +28,33 @@
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
},
{
"platform": "server",
"root": "src",
"outDir": "dist/server",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.server.ts",
"test": "test.ts",
"tsconfig": "tsconfig.server.json",
"prefix": "app",
"styles": [
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}

],
"addons": [
"../node_modules/font-awesome/fonts/*.+(otf|eot|svg|ttf|woff|woff2)"
Expand Down
32 changes: 20 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,39 @@
"test": "ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "protractor",
"publish-gh-pages": "ng build --base-href=/sample-app-angular/ && shx rm -rf pages && shx mkdir pages && cd pages && git init && git remote add pages https://github.com/ui-router/sample-app-ng2.git && git fetch pages && git checkout gh-pages && git rm -rf * && shx mv ../dist/* . && git add . && git commit -m 'Update gh-pages' . && cd .. && shx rm -rf pages"
"publish-gh-pages": "ng build --base-href=/sample-app-angular/ && shx rm -rf pages && shx mkdir pages && cd pages && git init && git remote add pages https://github.com/ui-router/sample-app-ng2.git && git fetch pages && git checkout gh-pages && git rm -rf * && shx mv ../dist/* . && git add . && git commit -m 'Update gh-pages' . && cd .. && shx rm -rf pages",
"build:dynamic": "npm run build:client-and-server-bundles && npm run webpack:server",
"serve:dynamic": "node dist/server.js",
"build:client-and-server-bundles": "ng build --prod && ng build --prod --app 1 --output-hashing=false",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors"
},
"private": true,
"dependencies": {
"@angular/common": "4.4.4",
"@angular/compiler": "4.4.4",
"@angular/core": "4.4.4",
"@angular/forms": "4.4.4",
"@angular/http": "4.4.4",
"@angular/platform-browser": "4.4.4",
"@angular/platform-browser-dynamic": "4.4.4",
"@angular/router": "4.4.4",
"@ngtools/webpack": "1.7.2",
"@angular/animations": "4.4.6",
"@angular/common": "4.4.6",
"@angular/compiler": "4.4.6",
"@angular/core": "4.4.6",
"@angular/forms": "4.4.6",
"@angular/http": "4.4.6",
"@angular/platform-browser": "4.4.6",
"@angular/platform-browser-dynamic": "4.4.6",
"@angular/platform-server": "4.4.6",
"@angular/router": "4.4.6",
"@ngtools/webpack": "1.7.4",
"@nguniversal/module-map-ngfactory-loader": "^1.0.0-beta.3",
"@uirouter/angular": "1.0.0-beta.7",
"@uirouter/visualizer": "4.0.2",
"bootstrap": "^3.3.7",
"core-js": "2.5.1",
"font-awesome": "^4.7.0",
"rxjs": "5.4.3",
"ts-helpers": "^1.1.1",
"ts-loader": "^3.0.5",
"zone.js": "0.8.5"
},
"devDependencies": {
"@angular/cli": "1.4.4",
"@angular/compiler-cli": "4.4.4",
"@angular/cli": "1.4.9",
"@angular/compiler-cli": "4.4.6",
"@types/jasmine": "2.5.38",
"@types/node": "^6.0.42",
"@types/whatwg-fetch": "0.0.33",
Expand Down
57 changes: 57 additions & 0 deletions server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');

// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');

const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');

app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
// Our index.html
document: template,
url: options.req.url,
// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
});

// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
5 changes: 4 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { routerConfigFn } from './router.config';
config: routerConfigFn,
}),
GlobalModule,
BrowserModule,
// Add .withServerTransition() to support Universal rendering.
// The application ID can be any identifier which is unique on
// the page.
BrowserModule.withServerTransition({appId: 'my-app'}),
FormsModule,
HttpModule
],
Expand Down
18 changes: 18 additions & 0 deletions src/app/app.server.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';

import {AppModule} from './app.module';
import { UIView } from '@uirouter/angular';

@NgModule({
imports: [
// The AppServerModule should import your AppModule followed
// by the ServerModule from @angular/platform-server.
AppModule,
ServerModule,
],
// Since the bootstrapped component is not inherited from your
// imported AppModule, it needs to be repeated here.
bootstrap: [UIView],
})
export class AppServerModule {}
4 changes: 0 additions & 4 deletions src/app/router.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { UIRouter, Category } from '@uirouter/core';
import { Visualizer } from '@uirouter/visualizer';

import { googleAnalyticsHook } from './util/ga';
import { requiresAuthHook } from './global/auth.hook';

export function routerConfigFn(router: UIRouter) {
const transitionService = router.transitionService;
requiresAuthHook(transitionService);
googleAnalyticsHook(transitionService);

router.trace.enable(Category.TRANSITION);
router.plugin(Visualizer);
}
6 changes: 6 additions & 0 deletions src/main.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare const global;
global.window = global;

import 'rxjs/add/operator/map';
export { AppServerModule } from './app/app.server.module';

24 changes: 24 additions & 0 deletions src/tsconfig.server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"mapRoot": "./",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/out-tsc",
"sourceMap": true,
"target": "es5",
"skipLibCheck": true,
"typeRoots": [
"../node_modules/@types"
]
},
// Add "angularCompilerOptions" with the AppServerModule you wrote
// set as the "entryModule".
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule"
}
}
32 changes: 32 additions & 0 deletions webpack.server.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const path = require('path');
const webpack = require('webpack');

module.exports = {
entry: { server: './server.ts' },
resolve: { extensions: ['.ts', '.js'] },
target: 'node',
// this makes sure we include node_modules and other 3rd party libraries
externals: [/(node_modules|main\..*\.js)/],
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader', options: { configFile: 'src/tsconfig.server.json'} }
]
},
plugins: [
// Temporary Fix for issue: https://github.com/angular/angular/issues/11580
// for "WARNING Critical dependency: the request of a dependency is an expression"
new webpack.ContextReplacementPlugin(
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src')
)
]
}

0 comments on commit b642962

Please sign in to comment.