Skip to main content

Overview

The Jhonny Diaz Portfolio is designed as a single-page application with no client-side routing. All sections (Header, Hero, About, Projects, Contact, Footer) are rendered on a single page without navigation between different routes. However, the application includes routing configuration files for future extensibility and server-side rendering (SSR) support.

Client-Side Routing

Routes Configuration

The client-side routes are defined in app.routes.ts:
import { Routes } from '@angular/router';

export const routes: Routes = [];
Current state:
  • The routes array is empty ([])
  • No route navigation is configured
  • The application renders a single page layout

Application Configuration

Routing is registered in the application configuration:
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideZonelessChangeDetection(),
    provideRouter(routes), 
    provideClientHydration(withEventReplay())
  ]
};
Key providers:
  1. provideBrowserGlobalErrorListeners() - Global error handling
  2. provideZonelessChangeDetection() - Modern zoneless change detection for better performance
  3. provideRouter(routes) - Router configuration (currently empty routes)
  4. provideClientHydration(withEventReplay()) - SSR hydration with event replay
Zoneless Change Detection is a modern Angular feature that improves performance by eliminating Zone.js dependency. The application uses signals and explicit change detection instead.

Server-Side Routing

Server Routes Configuration

The server-side routes are defined in app.routes.server.ts:
import { RenderMode, ServerRoute } from '@angular/ssr';

export const serverRoutes: ServerRoute[] = [
  {
    path: '**',
    renderMode: RenderMode.Prerender
  }
];
Configuration details:
  • path: '**' - Matches all routes (wildcard)
  • RenderMode.Prerender - Prerenders the HTML at build time

Render Modes

Angular SSR supports three render modes:

Prerender

Generates static HTML at build timeBest for: Static content, SEO

Server

Renders HTML on the server per requestBest for: Dynamic content

Client

Renders in the browser onlyBest for: Client-side apps
This portfolio uses Prerender mode because the content is static and doesn’t require server-side rendering per request. This provides the best performance and SEO benefits.

Single-Page Architecture

Why No Routing?

The portfolio is intentionally designed as a single-page application:
Users can scroll through all sections smoothly without page reloads or navigation clicks.
Navigation is handled through anchor links and smooth scrolling to sections.
All content loads once, eliminating the need for subsequent route-based loads.
Most portfolio websites benefit from a single-page layout showcasing all information at once.

Section-Based Navigation

Instead of route-based navigation, the portfolio uses section IDs for smooth scrolling:
<!-- Example: Header navigation links -->
<a href="#hero">Home</a>
<a href="#about">About</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>

Future Extensibility

While the current implementation has no routes, the routing infrastructure is in place for future expansion.

Adding Routes

To add client-side routing in the future:
1

Define routes in app.routes.ts

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'blog', component: BlogComponent },
  { path: 'blog/:id', component: BlogPostComponent }
];
2

Add RouterOutlet to template

The RouterOutlet is already imported in app.ts:
imports: [RouterOutlet, Header, Hero, About, Projects, Contact, Footer]
Add it to app.html:
<router-outlet />
3

Update server routes

Configure server-side rendering for each route:
export const serverRoutes: ServerRoute[] = [
  { path: '', renderMode: RenderMode.Prerender },
  { path: 'blog', renderMode: RenderMode.Prerender },
  { path: 'blog/:id', renderMode: RenderMode.Server }
];

SSR and Hydration

The application is configured for server-side rendering:

Build Configuration

In angular.json:
"build": {
  "builder": "@angular/build:application",
  "options": {
    "browser": "src/main.ts",
    "server": "src/main.server.ts",
    "outputMode": "server",
    "ssr": {
      "entry": "src/server.ts"
    }
  }
}

Hydration with Event Replay

The application uses withEventReplay() for hydration:
provideClientHydration(withEventReplay())
Benefits:
  • Captures user events during hydration
  • Replays events after the app becomes interactive
  • Prevents event loss during the SSR-to-client transition
When adding new routes or components, ensure they are compatible with SSR. Avoid using browser-specific APIs like window or document without proper checks.

Best Practices

When adding routes, use lazy loading for better performance:
{
  path: 'blog',
  loadComponent: () => import('./blog/blog.component').then(m => m.BlogComponent)
}
Protect routes with guards for authentication or authorization:
{
  path: 'admin',
  canActivate: [AuthGuard],
  loadComponent: () => import('./admin/admin.component')
}
Use RenderMode.Prerender for static pages and RenderMode.Server for dynamic content.

Build docs developers (and LLMs) love