Getting started with Angular universal

There are many blogs that offers tutorial on angular universal. However, most of it has some issues. You can clone entire sample from here. Build and run instruction are given as well.

To get it working from scratch, my app is called webapp

ng new webapp --routing

cd webapp

ng g universal --client-project webapp

# New Render Engine
npm install @nguniversal/express-engine

# If using lazy loading
npm install @nguniversal/module-map-ngfactory-loader

npm install --save-dev express webpack ts-loader

# If using Firebase

npm install --save-dev ws xmlhttprequest


import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

declarations: [
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule, BrowserTransferStateModule
providers: [],
//bootstrap: [AppComponent]
export class AppModule { }


import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule} from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';

import { AppModule } from './app.module';
import { AppComponent } from './app.component';

imports: [
ModuleMapLoaderModule, ServerModule, AppModule,
bootstrap: [AppComponent],
export class AppServerModule {}

Create server.ts in webapp root (not webapp/src folder) and ensure you change your APP_NAME, if you're not using webapp

// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';

// DOM libs required for Firebase
(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;

import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

import { join } from 'path';

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

const {
} = require(`./dist/${APP_NAME}-server/main`);


const app = express();

// Set the engine
bootstrap: AppServerModuleNgFactory,
providers: [provideModuleMap(LAZY_MODULE_MAP)]

app.set('view engine', 'html');

app.get('/**/*', (req, res) => {
res.render(join(DIST_FOLDER, APP_NAME, 'index'), {

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

// Static Assets
app.get('*.*', express.static(join(DIST_FOLDER, APP_NAME)));

// Point all routes to Universal
app.get('*', (req, res) => {
res.render('index', { req });

// Start Express Server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);

Create webpack.server.config.js again on webapp (root - not in webapp/src) and gain, please change your APP_NAME to your application name if you're not using webapp. Phew feel like a grandfather for reminding this again.

const path = require('path');
const webpack = require('webpack');

const APP_NAME = 'webapp';

module.exports = {
entry: { server: './server.ts' },
resolve: { extensions: ['.js', '.ts'] },
mode: 'none',
target: 'node',
externals: [/(node_modules|main\..*\.js)/],
output: {
path: path.join(__dirname, `dist/${APP_NAME}`),
filename: '[name].js'
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
parser: { system: true }
plugins: [
new webpack.ContextReplacementPlugin(
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
new webpack.ContextReplacementPlugin(
path.join(__dirname, 'src'),

edit your package.json and add in the followings. Remember to change your app name (Line 1 and 2)

"build:ssr": "ng build --prod && ng run webapp:server && npm run webpack:server",
"serve:ssr": "node dist/webapp/server.js",
"webpack:server": "webpack --config webpack.server.config.js"

Now to build and run your a

npm run build:ssr && npm run serve:ssr

Next, browse to http://localhost:4000


Popular posts from this blog

Solving Sonarqube :- Project was never analyzed. A regular analysis is required before a branch analysis

spark - pyspark reading from excel files