Pre-rendering frontend with Angular Universal & Firebase Hosting
Tags: angular, firebase, webdev, beginners
Published: 2023-01-16 12:27:05

Nowadays, if you want to build a front-end application, Angular comes first in mind. This [frontend development](https://quokkalabs.com/frontend-development) framework resembles the features and accessibility of the single-page application. Angular is best known for client-side rendering(frontend development), but it stretches the functionalities on the server side. The Angular Universal responds to this part.

## How does Angular Universal differ from Angular?
One major difference between Angular and Angular Universal is their execution environment. Angular manages the js download and rendering and prepares the dynamics at the browser first, whereas Angular Universal serves on the server side.

## What is the need for Angular Universal?
When we plan an angular based project for rendering, first, JS is downloaded on the browser side; then, the rendering begins inside the browser. After that, the user for further actions. We can't predict things at rapid speed, but things get delayed by poor connectivity. JS files take more time to download and render. Nothing will appear on the webpage.

Angular Universal emerged as an exclusive and exceptional tool to take care of such issues. However, you don’t have any access to make angular script changes. But it can offer pre-rendering on the server side. At the same time, it is waiting for the status of the JS download. Both processes will run subsequently and seamlessly. This action will reduce the load duration at the browser and deliver a fast response.

With Angular Universal support or mutual integration of **Angular Firebase Hosting**, users can interact with the webpage despite poor connectivity.

Also, Get to know the accessibility and practices of firebase remote configuration. 

**Access the blog:** 
{% embed https://dev.to/quokkalabs/firebase-remote-config-on-android-116 %}

Angular Universal has comforted three most interesting things:

- Performance Enhancement for mobile devices/ low-powered devices
- SEO Support 
- Rendering in low connectivity

## Angular Universal and Firebase Hosting- perfect for server-side rendering
Integration of Angular Firebase hosting ecosystem enables faster dynamic content delivery to angular based frontend development. To access the features of Angular Universal, hit this command in the terminal.

`ng add @nguniversal/express-engine –clientProject projectname`

It will enable the server-side application rendering accessibilities. 

The **angular.json** file contains the project name. You can get all the pre-rendering stuff from here. If you are using an older version of Angular 8, you may lack some accessibility. To resolve any inconvenience, please import **ModuleMapLoader**. You can access the site from the import section as app.server.module.ts.

Hit this command, and it will appear on the screen:
`npm install –save @nguniversal/module-map-ngfactory-loader` 

You can save your efforts importing this module if you have angular 9 or above support.

This thing is great from a user experience point of view. Users won’t be disappointed by slow loading issues when interacting with the application. 

Server-side and browser-side methods are different. It will impact application production. We can swap the methods to align the requirements. You can check the type of platform to avoid the application build.

Use **@angular/ common** method and inspect the platform type.

If you are building an angular-based application, then you need a dynamic host. You could only manage the full server-side rendering with a Node Js server.

To initiate the angular application build, hit this command: 
`npm run build:ssr`

Then, install and setup the Node.js server and hit the command: 
`npm run serve:ssr`

With these one-liner commands, you can manage the pre-rendering of essential dynamics.

### The process to Setup Firebase Hosting for Angular Universal

To streamline the instant rendering for the first page following the angular universal, we also need to integrate this angular firebase hosting.

#### Firebase-tools installation
Firebase also has a suite of resources that need to be installed for seamless integration. Hut the command:
`npm i -g firebase-tools`

#### Platform server installation
Next, you need to access the platform server accessibilities for that, copy this command and hit on the terminal:
`npm i --save @angular/platform-server`

#### Now access **app.module.ts** to make changes **BrowserModule**
```
imports: [
    BrowserModule.withServerTransition({ 
      appId: 'project_name' 
    }),
    AppRoutingModule
  ],
`
"projects": {
    "project_name": {
      "root": "",
```

Access **src/app** and create **app.server.module.ts** and use this inside
```
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 { }
```

#### Now create another file to src naming as **main.server.ts**
`export { AppServerModule } from './app/app.server.module';`

#### We need to add a **tsconfig.server.json.** It’s a file.
```
{
    "extends": "../tsconfig.json",
    "compilerOptions": {
      "outDir": "../out-tsc/app",
      "baseUrl": ".",
      "module": "commonjs",
      "types": []
    },
    "exclude": [
      "test.ts",
      "**/*.spec.ts"
    ],
    "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
    }
}
```

#### Do customization to **angular.json**
Go to **architect** and include server  after **lint**

```
"lint" : {
    ...
}, "server": {
      "builder": "@angular-devkit/build-angular:server",
      "options": {
        "outputPath": "functions/dist/server",
        "main": "src/main.server.ts",
        "tsConfig": "src/tsconfig.server.json"
      }
    }
```
Follow the path for the additional changes: Access **build, then options then outputPath**
```
"build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "functions/dist/browser",
```

#### Now initialize the production for the browser and server.
`ng build --prod`
`ng run project_name:server`

#### Initiate the setup for firebase
**firebase init**

- Do further important things: functions, hosting.
- Also, look for the firebase console and the project you want to work
- Then add Js cloud functions
- ESLint: No
- Disable Dependency installation for now
- Set the status public for the public directory
- Enable single-page app configuration

#### Access the Function Directory and eliminate the scripts block, go to the root directory and access angular project **package.json**, and add the dependencies here. Remember that your project's version and dependencies vary, so please check.

```
{
  "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
}
```

#### Access the Angular project’s root directory for function installation and execute the below command:
`npm --prefix functions install`

#### Access the functions directory and look for **index.js. Remove the existing code and add the below piece of 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);
```

#### Access the root directory and look for **firebase.json the eliminate the existing content: with this**:
```
{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source" : "**/*.@(css|js)",
        "destination": "/index2.html"
      },
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  }
}
```

#### Access the public directory and add the build files link, which you can execute from root directory.
`cp -a functions/dist/browser/. public/
mv public/index.html  public/index2.html`

#### See the demo in the local ecosystem
`firebase serve --only functions, hosting`

**Here the firebase setup is completed!**
### Angular Universal Integration with Firebase

- You need Angular Universal Integration or Angular Firebase Hosting to manage the pre-rendering of Angular project dynamic content.
`ng add @nguniversal/express-engine`

**You can add as many routes you desire for your project pre-rendering.**
```
{
  "prerender": {
    "builder": "@nguniversal/builders:prerender",
    "options": {
      "routes": [
        "/",
        "ANOTHER_ROUTE",
        "AND_ANOTHER"
      ]
    },
    "configurations": {
      /* ... */
    },
    "defaultConfiguration": "production"
  }
}
```

You can customize the SSR settings by eliminating the serverTarget and accessing the exclusive pre-rendering.
```
{
  "deploy": {
    "builder": "@angular/fire:deploy",
    "options": {
      "browserTarget": "app:build:production",
      "serverTarget": "app:server:production",
      "prerenderTarget": "app:prerender:production"
    }
  }
}
```

**Here the process of Angular Universal and Firebase Hosting finish. There are many things that are optional as per requirement.**

Deploy your single-page application **frontend development** project seamlessly, managing exclusive pre-rendering access. Furthermore, here is another blog to build a full stack application blending the functionalities of angular with nestjs and next.

{% embed https://quokkalabs.hashnode.dev/roadmap-for-full-stack-application-with-angular-nestjs-and-nx %}

Hope, this blog would worthy for you in your next projects!