Codementor Events

Building a Universal Server Side Rendered App with Angular 2+, Material Design 2 And Express.js

Published Aug 04, 2017

Universal Angular 2+ Apps

Throughout this tutorial we are going to build an example, server side rendered, web app with Angular 2+, Material Design 2 and Express server. The application is a simple portfolio website to showcase your projects with home ,projects and contact pages.

By building this demo project we'll learn how to create Angular 2+ web apps and how to render them on the server side (So you get a SEO friendly website), instead of client side, then serve them with Node.js and express server. We'll also learn how to use Material Design 2 with Angular 2+.

Generating a New Project

Lets get started by generating a new Angular 2+ web application using the Angular CLI.

ng new angular-universal-portfolio

Next run the local development server with:

cd angular-universal-portfolio ng serve

Your web app will be served from http://127.0.0.1:4200.

Adding Page Components

Next create the required page components (home, projects and contact) using Angular CLI:

ng g component home ng g component projects ng g component contact

Adding Material Design 2

To add Meterial Design 2 to your Angular 2+ project, you need to install these required dependencies:

npm install --save @angular/cdk
npm install --save @angular/material npm install --save hammerjs npm install --save-dev @types/hammerjs

Next you need to import MaterialModule and add to imports in app.module.ts

Don't also forget to import hammerjs

import { MaterialModule } from [email protected]/material'; import 'hammerjs'; @NgModule({
declarations: [AppComponent, HomeComponent, ContactComponent, ProjectsComponent],
imports: [BrowserModule.withServerTransition({appId: 'angular-universal-demo'}), FormsModule, HttpModule, MaterialModule, RouterModule.forRoot([ { path: '', component: HomeComponent, pathMatch: 'full'}, { path: 'projects', component: ProjectsComponent, pathMatch: 'full'}, { path: 'contact', component: ContactComponent, pathMatch: 'full'},]) ],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Before you can add Material2 components to your project you also have to add this to your project _styles.css_file:

@import '~https://fonts.googleapis.com/icon?family=Material+Icons';
@import '~https://fonts.googleapis.com/icon?family=Roboto';
@import [email protected]/material/prebuilt-themes/indigo-pink.css';
body { font-family: Roboto;
}

Then in tsconfig.app.json add:

Adding Server Side Rendering Support

To add server side rendering to our Angular 2+ app we need to install @angular/platform-server into our project:

npm install --save @angular/animations
npm install --save @angular/platform-server

Next we need to install ts-node:

npm install --save-dev ts-node

To add TypeScript support to Node.

We also need to install express server

npm install --save express

Since this is the server framework that we are going to use to render and serve our app on the server side.

Adding Server App Module

Create src/app/app.server.module.ts then add:

import { NgModule } from [email protected]/core';
import { ServerModule } from [email protected]/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component'; @NgModule({ imports: [ServerModule, AppModule], bootstrap: [AppComponent]
})
export class AppServerModule { }

Updating Client App Module

Next update src/app/app.module.ts to look like:

import { BrowserModule } from [email protected]/platform-browser';
import { NgModule } from [email protected]/core';
import { FormsModule } from [email protected]/forms';
import { HttpModule } from [email protected]/http';
import { RouterModule } from [email protected]/router'; import { HomeComponent } from './home/home.component';
import { ContactComponent } from './contact/contact.component';
import { ProjectsComponent } from './projects/projects.component'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent, HomeComponent, ContactComponent, ProjectsComponent], imports: [BrowserModule.withServerTransition({appId: 'angular-universal-demo'}), FormsModule, HttpModule, RouterModule.forRoot([ { path: '', component: HomeComponent, pathMatch: 'full'}, { path: 'projects', component: ProjectsComponent, pathMatch: 'full'}, { path: 'contact', component: ContactComponent, pathMatch: 'full'},]) ], providers: [], bootstrap: [AppComponent]
})
export class AppModule { }

Adding Server Code

Create src/server.ts then add:

import 'reflect-metadata';
import 'zone.js/dist/zone-node';
import { platformServer, renderModuleFactory } from [email protected]/platform-server'
import { enableProdMode } from [email protected]/core'
import { AppServerModuleNgFactory } from '../dist/ngfactory/src/app/app.server.module.ngfactory'
import * as express from 'express';
import { readFileSync } from 'fs';
import { join } from 'path'; const PORT = 5000; enableProdMode(); const app = express(); let template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString(); app.engine('html', (_, options, callback) => { const opts = { document: template, url: options.req.url }; renderModuleFactory(AppServerModuleNgFactory, opts) .then(html => callback(null, html));
}); app.set('view engine', 'html');
app.set('views', 'src') app.get('*.*', express.static(join(__dirname, '..', 'dist'))); app.get('*', (req, res) => { res.render('index', { req });
}); app.listen(PORT, () => { console.log(`listening on http://localhost:${PORT}!`);
});

Launching the Server

Next in package.json change start script to launch the express server:

"prestart": "ng build --prod && ngc",
"start": "ts-node src/server.ts"

Now run you express rendered web app with:

You server will be listenning from http://localhost:5000

You can visit this address from your browser then check the HTML source of the page to confirm that your app component, which says app works!, is rendered on the server

You should see something like:

<app-root _nghost-c0="" ng-version="4.3.1"><h1 _ngcontent-c0=""> app works!
</h1>
</app-root>

As you can notice, the AppComponent is rendered on the server.

Now serve your app using Angular CLI dev server:

Go to http://localhost:4200 with your browser then check the source code again:

<app-root>Loading...</app-root>

The AppComponent is not rendered on the server.

Creating the Portfolio Website

Now after setting up server side rendering and successfully launching the express server which renders and serves our Angular 2+ components, lets create our portfolio website. We have previously created the essential components: home, projects and contact then setup the routing for them in App Module:

RouterModule.forRoot([{ path: '', component: HomeComponent, pathMatch: 'full'}, { path: 'projects', component: ProjectsComponent, pathMatch: 'full'}, { path: 'contact', component: ContactComponent, pathMatch: 'full'},]) ]
Discover and read more posts from Ahmed Bouchefra
get started
post commentsBe the first to share your opinion
Show more replies