Skip to content

Instantly share code, notes, and snippets.

@debojyoti
Last active October 21, 2022 08:51
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save debojyoti/d75a517f77d8e5881d87553f1e493614 to your computer and use it in GitHub Desktop.
Save debojyoti/d75a517f77d8e5881d87553f1e493614 to your computer and use it in GitHub Desktop.

Angular Universal setup for firebase hosting

1) Install firebase-tools globally

npm i -g firebase-tools

2) Install @angular/platform-server

npm i --save @angular/platform-server

3) Modify BrowserModule in app.module.ts

imports: [
    BrowserModule.withServerTransition({ 
      appId: 'project_name' 
    }),
    AppRoutingModule
  ],

project_name can be found in angular.json

"projects": {
    "project_name": {
      "root": "",

4) Create a new file app.server.module.ts in src/app

Paste the following code

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';

@NgModule({
    imports: [
        ServerModule,
        AppModule
    ],
    bootstrap: [AppComponent]
})
export class AppServerModule { }

5) Create a new file main.server.ts in src

Paste the following code

export { AppServerModule } from './app/app.server.module';

6) Create a new file tsconfig.server.json in src

Paste the following code

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
      "outDir": "../out-tsc/app",
      "baseUrl": ".",
      "module": "commonjs",
      "types": []
    },
    "exclude": [
      "test.ts",
      "**/*.spec.ts"
    ],
    "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
    }
}

7) Modify angular.json

7.1) Add server block after lint, within architect

"lint" : {
    ...
}, "server": {
      "builder": "@angular-devkit/build-angular:server",
      "options": {
        "outputPath": "functions/dist/server",
        "main": "src/main.server.ts",
        "tsConfig": "src/tsconfig.server.json"
      }
    }

7.2) Modify build > options > outputPath

"build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "functions/dist/browser",

Step-8) Build browser and server code

ng build --prod
ng run project_name:server

project_name is same as Step - 2

Step-9) Build browser and server code

ng build --prod
ng run project_name:server

Step-10) Init firebase

firebase init

10.1) Select functions and hosting 10.2) Select your project from firebase console 10.3) Select Javascript for cloud functions 10.4) ESLint: No 10.5) Dependency install now: No 10.6) public directory: public 10.7) Configure as a single-page app: Yes

Step-11) Modify package.json in functions directory

11.1) Remove scripts block 11.2) Add all dependencies from angular project's package.json (In root directory) Example

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "dependencies": {
    "firebase-admin": "~6.0.0",
    "firebase-functions": "^2.1.0",
    "@angular/animations": "~7.1.0",
    "@angular/common": "~7.1.0",
    "@angular/compiler": "~7.1.0",
    "@angular/core": "~7.1.0",
    "@angular/forms": "~7.1.0",
    "@angular/http": "^7.1.4",
    "@angular/platform-browser": "~7.1.0",
    "@angular/platform-browser-dynamic": "~7.1.0",
    "@angular/platform-server": "^7.1.4",
    "@angular/router": "~7.1.0",
    "core-js": "^2.5.4",
    "rxjs": "~6.3.3",
    "tslib": "^1.9.0",
    "zone.js": "~0.8.26"
  },
  "private": true
}

Note: Versions and list of dependencies will be different in your project

Step-12) Install function

12.1) From the root directory of angular project, run

npm --prefix functions install

Step-13) Modify index.js inside functions directory

Replace the content by the following code

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');

enableProdMode();

const index = require('fs')
  .readFileSync(path.resolve(__dirname, './dist/browser/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);

Step-14) Modify firebase.json in root directory

Replace the content by the following code


{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source" : "**/*.@(css|js)",
        "destination": "/index2.html"
      },
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  }
}

Step-15) Create build files link in the public directory

Run from root directory

cp -a functions/dist/browser/. public/
mv public/index.html  public/index2.html 

Step-16) Try in local environment

firebase serve --only functions,hosting

Step-17) Deploy!

firebase deploy

Bonus trick

1: There will be some cases where you may need to run different code while rendering in server side.

You can detect if the page is loaded in browser or not. Just modify the component's code as below

import { Component, Inject, PLATFORM_ID, OnInit } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
...

@Component({
  ...
})
export class AppComponent {

  ...
  
  constructor(
    ...,
    @Inject(PLATFORM_ID) private platformId: Object,
    ...
  ) {
  }

  ngOnInit() {
    ...
    if (isPlatformBrowser(this.platformId)) {
        window.location.replace('http://sidanmor.com');
       } else {
        //Server only code.
       }
       ...
  }
}
@broslukasz
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment