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-server
yarn add @angular/platform-server
-
Modify
main.server.ts
to the following:import { enableProdMode } from '@angular/core'; export { AppServerModule } from './app/app.server.module'; enableProdMode();
-
Add
/dist-server
to.gitignore
# compiled output /dist /dist-server ...
-
Build the app (
/dist
folder) and the server to render the app (/dist-server
folder).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
Functions
andHosting
for features - Select the firebase project you created (eg.
angular-universal-firebase
) - Select
javascipt
as the language used to write Cloud Functions - Select
no
to 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.json
file. IMPORTANT: Install dependencies in thefunctions
directory 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
functions
directory usingyarn
.yarn install
-
Copy the
dist
anddist-server
folders into thefunctions
directory. This is because Firebase functions cannot access files outside of this directory. There should now be exact copies of those two folders infunctions/dist
andfunctions/dist-server
, respectively. -
Create Firebase function (
index.js
) to serve the app. This file is found in thefunctions
directory.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.json
to:{ "hosting": { "public": "dist", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [{ "source": "**", "function": "ssr" }] } }
-
Delete the
/public
folder that was automatically generated by Firebase functions during thefirebase init
processrm -rf public
-
Delete
dist/index.html
from the root directory. This is so Firebase won’t serve the html file but rather run the ssr function. -
Add
functions/dist
,functions/dist-server
andfunctions/node_modules
to.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.