Server-Side Rendering (SSR) is a technique used to improve the performance and SEO of web applications by rendering pages on the server instead of the client. Angular Universal is a technology that enables SSR for Angular applications, allowing them to be rendered on the server and sent to the client as fully rendered pages. This article will guide you through the process of setting up SSR with Angular Universal, along with practical examples.
Why Use Server-Side Rendering?
Benefits of SSR
- Improved Performance: SSR can significantly reduce the time to first meaningful paint (TTFMP) by sending a fully rendered page to the client.
- Better SEO: Search engines can index content more effectively since the content is available in the HTML at the time of the initial load.
- Enhanced User Experience: Users see the content faster, which improves the overall user experience.
Drawbacks of SSR
- Increased Server Load: The server needs to render the HTML for each request, which can increase the load on the server.
- Complexity: Implementing SSR adds complexity to the application setup and development process.
Setting Up Angular Universal
Step 1: Create an Angular Application
First, create a new Angular application if you don’t have one already:
ng new angular-universal-example
cd angular-universal-example
Step 2: Add Angular Universal
Add Angular Universal to your existing Angular application:
ng add @nguniversal/express-engine
This command will perform the following tasks:
- Install necessary dependencies.
- Create server-side files (
server.ts
). - Update
angular.json
andpackage.json
to include new build and serve targets for SSR.
Step 3: Update the Server Configuration
Open the server.ts
file and update it as needed. Here’s an example configuration:
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';
const app = express();
const distFolder = join(process.cwd(), 'dist/angular-universal-example/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
app.set('view engine', 'html');
app.set('views', distFolder);
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
// Start up the Node server
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
Step 4: Build and Serve the Application
Build the application for SSR:
npm run build:ssr
Serve the application:
npm run serve:ssr
You can now access the server-rendered Angular application at http://localhost:4000
.
Example: Using Angular Universal with a Sample Component
To demonstrate the effectiveness of SSR, let’s create a sample component that displays a list of items fetched from an API.
Step 1: Create the Service
Create a service to fetch data from an API:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DataService {
constructor(private http: HttpClient) {}
getItems(): Observable<any[]> {
return this.http.get<any[]>('https://api.example.com/items');
}
}
Step 2: Create the Component
Create a component to display the fetched data:
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-item-list',
template: `
<ul>
<li *ngFor="let item of items">{{ item.name }}</li>
</ul>
`,
})
export class ItemListComponent implements OnInit {
items: any[] = [];
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.dataService.getItems().subscribe((data) => {
this.items = data;
});
}
}
Step 3: Update App Module
Add the component and service to your App Module:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { ItemListComponent } from './item-list/item-list.component';
import { DataService } from './item-list/data.service';
@NgModule({
declarations: [
AppComponent,
ItemListComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
HttpClientModule
],
providers: [DataService],
bootstrap: [AppComponent]
})
export class AppModule { }
Step 4: Update Server-Side Rendering Module
Make sure the server-side rendering module includes the necessary imports:
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
Conclusion
Server-Side Rendering with Angular Universal can significantly improve the performance and SEO of your Angular applications. By following the steps outlined in this article, you can set up SSR for your Angular application and experience the benefits firsthand.
Hashtags
#Angular #AngularUniversal #ServerSideRendering #SSR #WebDevelopment #JavaScript #Frontend #SEO #Performance #WebPerformance #FullStackDevelopment #TechBlog #WebOptimization #AngularDevelopment