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 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
Functions
and Hosting
for featuresangular-universal-firebase
)javascipt
as the language used to write Cloud Functionsno
to install dependencies with npmHosting
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 root package.json
file. IMPORTANT: Install dependencies in the functions
directory with yarn. NPM does not properly install firebase-admin
. You will have to install express using yarn 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 using yarn
.
yarn install
Copy the dist
and dist-server
folders into the functions
directory. This is because Firebase functions cannot access files outside of this directory. There should now be exact copies of those two folders in functions/dist
and functions/dist-server
, respectively.
Create Firebase function (index.js
) to serve the app. This file is found in the functions
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 the firebase init
process
rm -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
and functions/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.