Server side rendering using Angular4(Angular Universal) [closed] Server side rendering using Angular4(Angular Universal) [closed] angular angular

Server side rendering using Angular4(Angular Universal) [closed]


This Angular Universal is only for Angular 2. If you want to start from scratch you can use this Angular 4 Universal Seed which has all features like:

  • Angular 4
  • WebPack
  • dev/prod modes
  • SCSS compilation
  • i18n, SEO, and TSLint/codelyzer
  • lazy loading, config, cache

Or if you already had Angular 4 project running you can Integrate Universal by doing following settings in your code:

Install these packages:
npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@latest typescript@latest --save

npm install express @types/express --save-dev

Add this in your app.module.ts file

import { BrowserModule } from '@angular/platform-browser';BrowserModule.withServerTransition({  appId: 'my-app-id'   // withServerTransition is available only in Angular 4}),

Create following files

src/uni/app.server.ts

import { NgModule } from '@angular/core';import { APP_BASE_HREF } from '@angular/common';import { ServerModule } from '@angular/platform-server';import { AppComponent } from '../app/app';import { AppModule } from '../app/app.module';import 'reflect-metadata';import 'zone.js';@NgModule({  imports: [    ServerModule,    AppModule  ],  bootstrap: [    AppComponent  ],  providers: [    {provide: APP_BASE_HREF, useValue: '/'}  ]})export class AppServerModule {}


src/uni/server-uni.ts

import 'zone.js/dist/zone-node';import 'zone.js';import 'reflect-metadata';import { enableProdMode } from '@angular/core';import { AppServerModuleNgFactory } from  '../../aot/src/uni/app.server.ngfactory';import * as express from 'express';import { ngUniversalEngine } from './universal-engine';enableProdMode();const server = express();// set our angular engine as the handler for html files, so it will be used to render them.server.engine('html', ngUniversalEngine({    bootstrap: [AppServerModuleNgFactory]}));// set default view directoryserver.set('views', 'src');// handle requests for routes in the app.  ngExpressEngine does the rendering.server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req:any, res:any) => {    res.render('index.html', {req});});// handle requests for static filesserver.get(['/*.js', '/*.css'], (req:any, res:any, next:any) => {    let fileName: string = req.originalUrl;    console.log(fileName);    let root = fileName.startsWith('/node_modules/') ? '.' : 'src';    res.sendFile(fileName, { root: root }, function (err:any) {        if (err) {            next(err);        }    });});// start the serverserver.listen(3200, () => {    console.log('listening on port 3200...');});

src/uni/universal-engine.ts

import * as fs from 'fs';import { renderModuleFactory } from '@angular/platform-server';const templateCache = {}; // cache for page templatesconst outputCache = {};   // cache for rendered pagesexport function ngUniversalEngine(setupOptions: any) {  return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) {    let url: string = options.req.url;    let html: string = outputCache[url];    if (html) {      // return already-built page for this url      console.log('from cache: ' + url);      callback(null, html);      return;    }    console.log('building: ' + url);    if (!templateCache[filePath]) {      let file = fs.readFileSync(filePath);      templateCache[filePath] = file.toString();    }    // render the page via angular platform-server    let appModuleFactory = setupOptions.bootstrap[0];    renderModuleFactory(appModuleFactory, {      document: templateCache[filePath],      url: url    }).then(str => {      outputCache[url] = str;      callback(null, str);    });  };}

Add below configuration in your tsconfig.ts file which I assume located in root dir

{    "compilerOptions": {        "baseUrl": "",        "declaration": false,        "emitDecoratorMetadata": true,        "experimentalDecorators": true,        "lib": ["es2016", "dom"],        "moduleResolution": "node",        "outDir": "./dist/out-tsc",        "sourceMap": true,        "target": "es5",        "module": "commonjs",        "types": ["node"],        "typeRoots": [            "node_modules/@types"        ]    },    "files": [        "src/uni/app.server.ts",        "src/uni/server-uni.ts"    ],    "angularCompilerOptions": {        "genDir": "aot",        "entryModule": "./src/app/app.module#AppModule",        "skipMetadataEmit": true    },    "exclude": [        "test.ts",        "**/*.spec.ts"    ]}

Atlast your webpack.config.uni.js in root dir

const ngtools = require('@ngtools/webpack');const webpack = require('webpack');const path = require('path');const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");module.exports = {    devtool: 'source-map',    entry: {        main: ['./src/uni/app.server.ts', './src/uni/server-uni.ts']    },    resolve: {        extensions: ['.ts', '.js']    },    target: 'node',    output: {        path: path.join(__dirname, "dist"),        filename: 'server.js'    },    plugins: [        new ngtools.AotPlugin({            tsConfigPath: './tsconfig.json'        })    ],    module: {        rules: [            {                test: /\.(scss|html|png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,                use: 'raw-loader'            },            { test: /\.ts$/,  loader: require.resolve('@ngtools/webpack') },            {                test: /\.(png|jpg|woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,                loader: 'url?limit=512&&name=[path][name].[ext]?[hash]'            },            { test: /\.scss$/, use: [{                loader: "style-loader" // creates style nodes from JS strings            }, {                loader: "css-loader" // translates CSS into CommonJS            }, {                loader: "sass-loader" // compiles Sass to CSS            }] }        ]    }}

Add below scripts in you package.json file:

"ngc-build": "ngc -p ./tsconfig.json", // To generate ngFactory file"build:uni": "webpack --config webpack.config.uni.js","serve:uni": "node dist/server.js",

There are certain things that we should keep in mind:

  • window, document, navigator, and other browser types - do not exist on the server - so using them, or any library that uses them (jQuery for example) will not work. You do have some options given in this link if you truly need some of this functionality.


Angular universal is only used for angular 2.x. Angular 4.x you need to use platform server.Examples are as follows:

For angular 2.X.X :

AngularClass's seed project using express/universal

https://github.com/angular/universal-starter

For angular 4.X.X Use angular platform server

https://github.com/ng-seed/universal

There are few other examples also:


The example that is mentioned in given tutorial is using the example mentioned in Angular Resources section. They have recently updated their docs and have not yet provided the detailed documentation to implement @angular/universal. This used to be the page you are looking for but it had some issues mentioned here. May be that's why they removed it and have decided to rewrite it.