Lazy Panda

Developer

Posts
57
Comments
48
Likes
76
Posts
57
Comments
48
Likes
76
sidebar

Upgrade ng14 application to ng17 with SSR prerender and pwa enabled

 

Nowadays most of the popular frontend frameworks are releasing new updates and making the web application more promising. As per my understanding, frameworks like Angular, NextJs, and NuxtJs are not only frameworks to build a frontend application rather they also have the full scope of a node server and the developer can play with application logic on the server side or client side. 

ng14 to ng17 upgrade

In the same way, today I thought to upgrade my old Angular 14 application to Angular 17 and look through the challenges. Here, is my ng14 to ng17 version upgradation plan

ng14 to ng17 upgrade

From the above steps, first, you have had to upgrade your current version to the desired version and I continued to update the version regardless of any error. I did not run "ng build" ever during the process. Once my "yarn install" was successful, then I tried to build/compile my angular application with 17 versions. I do end up getting so many compilation errors, and the build fails. 

 

Now, let's see those buid errors and solve them individually.

Cannot access '<your angular module>' before initialization

This error I received because I have not injected my angular service files into the module as a provider. So I did the following - 

// @Injectable({

// providedIn: "root",

// })

@Injectable()

export class WidgetService {

<< Other code >>

}

@NgModule({

declarations: [],

imports: [],

providers: [

WidgetService

]

})

 

Can't find a stylesheet to import. @import '~bootstrap/scss/bootstrap'

When Sass is precompiled, it processes @imports by itself, and sometimes thus doesn’t understand ~ notation. So you can replace '~' with "node_modules" like below - 

@import "node_modules/bootstrap/scss/bootstrap";

Then if you do build now, you should not get scss related importing issue anymore. 

 

Update APP_ID for BrowserModule

Before ng v17, we have been using APP_ID on BrowserModule.withServerTransition({ appId: "serverApp" }). As per the documentation of Angular 17, we do not need to import BrowserModule anymore, we can add APP_ID as a provider, like below - 

@NgModule({

imports: [

CommonModule,

// BrowserModule.withServerTransition({ appId: "serverApp" }),

BrowserAnimationsModule,

]

})

@NgModule({

imports: [

CommonModule,

BrowserAnimationsModule,

],

providers: [

{ provide: APP_ID, useValue: "serverApp" },

]

})

 

After making all the changes, and running the "ng serve" the application should be run perfectly on the browser. But if your application is supporting SSR or Prerender then we still need to do a few more steps to resolve the application compilation error.

 

If your application supports Server Side Rendering or Prerendering, then you need to add yarn add @angular/ssr@17.2.2 & yarn add @nguniversal/express-engine@16.2.0

This above command will update the necessary code to our application, like below - 

  1. Update the server.ts file and create a backup file with your old code in server.ts.bak file.
  2. The new server.ts file is trying to import bootstrap from main.server file. 
  3. For that, the new code will expect app.config.ts and app.server.config.ts files created.
  4. Import the application config into main.server.ts file and export the bootstarp for server.ts file

All the above I tried and understood, this is not the right time or I can't spend that much effort to update my NgModule application to a StandAloneComponent application. 

So I still use my old code -

  • Keep server.ts as is
  • Do not create app.config.ts & app.server.config.ts file
  • Do not update main.server.ts file

After doing all of them, run ng run blog-fe:serve-ssr --port 4500 to execute my SSR-enabled application, and it works fine. 

main.ts

import { enableProdMode } from "@angular/core";

import { environment } from "./environments/environment";

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppBrowserModule } from "./app/app.browser.module";

 

if (environment.production) {

enableProdMode();

}

 

document.addEventListener("DOMContentLoaded", () => {

platformBrowserDynamic()

.bootstrapModule(AppBrowserModule)

.catch((err) => console.error(err));

});

 

// bootstrapApplication(AppComponent, appConfig).catch((err) =>

// console.error(err)

// );

 

main.server.ts

import { enableProdMode } from "@angular/core";

import { environment } from "./environments/environment";

 

if (environment.production) {

enableProdMode();

}

 

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

export { renderModule } from "@angular/platform-server";

 

 

Let's say if you want to create a Prerender build, again the same code may throw an error to you, as I have got few. Such as - 

An unhandled exception occurred: Right-hand side of 'instanceof' is not an object

This issue is being happening from your server.ts file. Earlier I used to have domino to create a window, but now I tried with ssr-window, and it worked well. Here is my server.ts file code, may this will help you.

 

 

Now, I run the prerender build command with my route.txt file, ng run blog-fe:prerender --routes-file routes.txt and it is able to compile the code successfully and generate prerender pages accordingly.

Enable PWA to Angular 17 application

To add pwa feature to your angular application, we need to add ng add @angular/pwa, it will install @angular/service-worker and create ngsw-config.json and manifest.webmanifest file. 

After all of this, the application must be working for all aspects in the development environment as well as the production environment. Let me also add the following commands which I have been using for development and production environment. 

 

Command Type Description
development This command should open the application on different port (e.g - 4500) - ng serve --port 4500
development SSR This command helps to execute the application on the node server and generates Server generated Pages ng run blog-fe:serve-ssr --port 4500
production SSR

We need to run two commands for this regard - 

  1. Build SSR (dev:ssr) - ng build --configuration production && ng run <Project Name>:server:production
  2. Run (serve:ssr) - node dist/<Project Name>/server/main.js
Production Prerender

To create a prerender build, we need to pass the routes explicitly 

  1. Prerender Build (prerender-build) - ng run blog-fe:prerender --routes-file routes.txt
  2. Run (start) - http-server -c-1 -a localhost -p 4500 ./dist/<Project Name>/browser
PWA enable

To enable PWA with your prerender build - 

  1. Prerender Build & enable PWA (prerender) - npm run list-routes && ng run blog-fe:prerender --routes-file routes.txt && npm run enable-pwa
  2. Enable PWA (enable-pwa) - ./node_modules/.bin/ngsw-config ./dist/<Project Name>/browser ./ngsw-config.json
  3. Run (start) - http-server -c-1 -a localhost -p 4500 ./dist/<Project Name>/browser

 

Hope with all settings you can make up the application for ng17. If you are still facing any challenges or other errors due to upgradation, feel free to post them. I can look into them and suggest probable solutions that might help our dev community be strong. 

Happy Coding!

-LP