This step-by-step tutorial will show you how to deploy a Angular App with server-side rendering using Angular Universal with Firebase Hosting. This project was generated with Angular CLI version 1.7.1.
- Angular version: 5.2.6
- Firebase CLI version: 3.17.4
Angular CLI has native Universal support starting from v1.6. We will use the CLI to quickly generate Angular Universal server files, and then make some minor changes for our production build.
-
Create a new Angular project
ng new angular-universal-firebase -
Generate Angular Universal using Angular CLI (v1.6 or greater)
ng generate universal universal -
Install
@angular/platform-serveryarn add @angular/platform-server -
Modify
main.server.tsto the following:import { enableProdMode } from '@angular/core'; export { AppServerModule } from './app/app.server.module'; enableProdMode();
-
Add
/dist-serverto.gitignore# compiled output /dist /dist-server ... -
Build the app (
/distfolder) and the server to render the app (/dist-serverfolder).ng build --prod && ng build --prod --app universal --output-hashing=none
Since we now have an Angular app with a /dist and /dist-server directories, we will now use Firebase Cloud Functions to serve our application. This guide was originally written by Aaron Te and can be found at Hackernoon: Deploy Angular Universal w/ Firebase, but has been slightly modified with minor changes.
-
Create a Firebase project (eg.
angular-universal-firebase) -
Log in to firebase using
firebase login -
Initialize Firebase in the Angular project
firebase init- Select
FunctionsandHostingfor features - Select the firebase project you created (eg.
angular-universal-firebase) - Select
javasciptas the language used to write Cloud Functions - Select
noto install dependencies with npm - Select all defaults for
Hosting
- Select
-
Add Angular dependencies to
functions/package.json, including @angular, rxjs, and zone.js. The easiest way to add these dependencies will be to copy them from your rootpackage.jsonfile. IMPORTANT: Install dependencies in thefunctionsdirectory with yarn. NPM does not properly installfirebase-admin. You will have to install express usingyarn add express."dependencies": { "@angular/animations": "^5.2.6", "@angular/common": "^5.2.6", "@angular/compiler": "^5.2.6", "@angular/core": "^5.2.6", "@angular/forms": "^5.2.6", "@angular/http": "^5.2.6", "@angular/platform-browser": "^5.2.6", "@angular/platform-browser-dynamic": "^5.2.6", "@angular/platform-server": "^5.2.6", "@angular/router": "^5.2.6", "express": "^4.16.2", "firebase-admin": "~5.9.0", "firebase-functions": "^0.8.1", "rxjs": "^5.5.6", "zone.js": "^0.8.20" },
-
Install all dependencies in the
functionsdirectory usingyarn.yarn install -
Copy the
distanddist-serverfolders into thefunctionsdirectory. This is because Firebase functions cannot access files outside of this directory. There should now be exact copies of those two folders infunctions/distandfunctions/dist-server, respectively. -
Create Firebase function (
index.js) to serve the app. This file is found in thefunctionsdirectory.require('zone.js/dist/zone-node'); const functions = require('firebase-functions'); const express = require('express'); const path = require('path'); const { enableProdMode } = require('@angular/core'); const { renderModuleFactory } = require('@angular/platform-server'); const { AppServerModuleNgFactory } = require('./dist-server/main.bundle'); enableProdMode(); const index = require('fs') .readFileSync(path.resolve(__dirname, './dist/index.html'), 'utf8') .toString(); let app = express(); app.get('**', function (req, res) { renderModuleFactory(AppServerModuleNgFactory, { url: req.path, document: index }).then(html => res.status(200).send(html)); }); exports.ssr = functions.https.onRequest(app);
-
Update
firebase.jsonto:{ "hosting": { "public": "dist", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [{ "source": "**", "function": "ssr" }] } } -
Delete the
/publicfolder that was automatically generated by Firebase functions during thefirebase initprocessrm -rf public -
Delete
dist/index.htmlfrom the root directory. This is so Firebase won’t serve the html file but rather run the ssr function. -
Add
functions/dist,functions/dist-serverandfunctions/node_modulesto.gitignore# compiled output /dist /dist-server /functions/dist /functions/dist-server ... # dependencies /node_modules /functions/node_modules -
Deploy to Firebase
firebase deploy
To get more help on the Angular CLI use ng help or go check out the Angular CLI README.