Angular 17 Upgrade Guide with SSR
Tags: angular, ssr, javascript, upgrade
Published: 2024-02-25 09:22:32

---
title: Angular 17 Upgrade Guide with SSR
published: true
description: Learn how to upgrade your existing app to Angular v17
tags: #angular #ssr #javascript #upgrade
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eow8eekfvaybt5jhf7bp.png
# Use a ratio of 100:42 for best results.
# published_at: 2024-02-23 18:03 +0000
---

I was recently asked to upgrade the existing Angular app with a new Angular SSR framework. However, what I didn't know at the time is that Angular SSR only works on Angular 17. So I'm writing this guide that will teach you how to upgrade your existing Angular app to v17 as well as add server-side rendering.

## Node.js Compatibility 🌐
Since Angular depends on Node.js, you need to have compatible versions of both. That’s why the Angular team has this [compatibility table](https://angular.io/guide/versions) to let you know which version of Node.js is compatible with the version of Angular.

![angular-node-compatibility-table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru9ep045jnf0cpf39y40.png)

If you need to upgrade your Node.js version, be sure to go to [Nodejs.org](https://nodejs.org/) and download the recommended version or use the [NVM](https://www.freecodecamp.org/news/node-version-manager-nvm-install-guide/) instead:

```bash
> nvm install 18 # Install Node.js v18

> nvm use 18 # Switch to installed version

# Now using node v18.x.x
```

Since I was using Angular 16 with Node.js 18, I didn't need to change my Node.js version.


## Ng Update 🕹️
The easiest way to upgrade to a newer version of Angular is to execute the `ng update` command in your CLI in the project folder.

Upon running the command you'll get tips on what to upgrade, e.g.

```bash
> ng update

You need to manually upgrade the following:
Angular CLI => ng update @angular/cli 
Angular Core => ng update @angular/core 
Angular CDK => ng update @angular/cdk
...
```

### Angular CLI
To get started, upgrade your current CLI version to the latest one:

```bash
> ng update @angular/cli 
```

Upon updating the CLI you might be prompted to commit your changes to the Git before proceeding.

### Angular Core
The next step is to upgrade the Angular framework, which you do using:

```bash
> ng update @angular/core 
```
The core framework is now upgraded to v17 which you'll notice in the dependencies list in your package.json file.

### Angular Material
Since I'm using Angular Material in my project I needed to upgrade it before continuing with the rest of the updates.

```bash
> ng update @angular/material 
```

### Angular CDK
With Material sorted out, I installed the last mandatory update (on the previous list) which was Angular CDK:

```bash
> ng update @angular/cdk
```

Now the project should be fully migrated to the latest version.

For some reason, I also needed to fix the paths of all the imports of my custom components, services, models, etc, and TSConfig errors [(which you can solve by copying the tsconfig from here)](https://github.com/ganatan/angular-ssr/blob/master/tsconfig.json), but this is a pretty small complaint. 


## Adding Angular SSR 🚀
The new Angular/SSR package replaces the Angular Universal. The new framework is faster and more intuitive.

```bash
> ng add @angular/ssr # installs Angular SSR
```

For those of you coming from Next.js, Angular uses Express.js to handle the backend routing and `CommonEngine` [(from Angular/SSR)](https://angular.io/guide/ssr) for rendering an Angular app on the Express.js server.

### Fixing Config Imports
Upon setting up the Angular SSR framework, Angular will create a `server.ts` (Express.js file that loads the app) and a `main.server.ts` file (that is equivalent to Angular App Module but for the server).
You may run into an issue with the current Angular config not knowing the correct path of the two newly added files.

Make sure to set this properties to current paths:

#### angular.json/build/options

```json
    "server": "src/main.server.ts", // path to your file
```

#### tsconfig.app.json

```json
  "files": [
    "src/main.ts", // path to your file
    "src/main.server.ts", // path to your file
    "server.ts"
  ],
```

### HTTP Client Configuration
Upon running the HTTP services with SSR, Angular might throw this error:
`NG02801 is not an error but a warning that encourages the developers to enable the fetch implementation of the HttpClient.`

To resolve it, you need to add `provideHttpClient(withFetch())` to your app.config.ts file or app.module.ts (if you're using the old NgModules):

```ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch  } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideClientHydration(),
    provideHttpClient(withFetch()), // here it is!
  ],
};
```

### Connecting Frontend & Backend
As a proof of concept, create a dummy endpoint in the `server.ts` file:

```ts
  server.get('/api/greetings', (req: express.Request, res: express.Response) => {
    res.send({ message: 'Hello from Angular SSR!' });
  });
```

Generate a new Angular service using:

```bash
> ng g s services/greetings
```

And connect to your API via HTTP Client:

```ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

interface IGreetings {
  message: string
}

@Injectable({
  providedIn: 'root'
})
export class GreetingService {

  // alternative to the class constructor
  private readonly httpClient = inject(HttpClient);

  getGreetings(): Observable<IGreetings> {
    return this.httpClient.get<IGreetings>('/api/greetings');
    // notice how you don't need to prefix your route with localhost:PORT 
    // because it's coming from the same domain
  }
}
```
Create a button element inside the App Component (or any other component):

```html
<button (click)="sayHello()">Say Hello!</button>
```

And register a handler for this button within the TypeScript file. This handler will invoke the service you've just created.

```ts
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { GreetingService } from './services/greeting.service';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {

  private readonly greetingsService = inject(GreetingService);

  sayHello() {
    this.greetingsService.getGreetings().subscribe(console.log)
  }
}
```

### Running the App
Firstly build the app using the build script from the package.json file:

```json
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "serve:ssr": "node dist/<your-app>/server/server.mjs"
  },
```

```bash
> ng build # or npm run build
```
This will contain a `dist` folder in your main directory containing `browser` and `server` directories.

Then run the server and the client using the `server:ssr` script:

```bash
> npm run serve:ssr

> <your-app>y@0.0.0 serve:ssr
> node dist/<your-app>/server/server.mjs

Node Express server listening on http://localhost:4000
```

If you then click the button on UI, you should see a message from the API printing in the console.

![preview-msg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bt9qdob6s24dzcjhyonm.png)

And that's it!

## Why Angular 17 🎉
Angular 17 is a new iteration of the popular frontend framework made by Google. Version 17 ships with a host of exciting new features:
* New control flow
* Deferrable views
* New Server-Side-Rendering framework
* New Docs
* Signal-based component inputs and two-way binding, just to name a few.

That's all from me today. 
If you'd like to learn more about Angular, make sure to check out my other blog on [Medium](https://mirzaleka.medium.com/list/angular-starter-8a76b9970678) and follow me on [Twitter](https://twitter.com/mirzaleka) to stay up to date with my content updates.

Bye for now 👋