Skip to content

@braidlabs/angular-router ​

Resilient chunk recovery and version skew handling for Angular applications. Classifies lazy-route failures, probes deployment manifests, and recovers cleanly without reload loops or lost form inputs.


Installation ​

bash
npm install @braidlabs/angular-router @braidlabs/build

The Problem: Stale Lazy Chunks ​

When a deployment lands while users are active, navigating to a lazy-loaded route throws a ChunkLoadError because the older hashed chunk was removed from the CDN. Blindly calling location.reload() can cause infinite reload loops if CDN edges or service workers are out of sync.

@braidlabs/angular-router solves this with:

  1. Pre-Classification Retry: Retries transient CDN misses with exponential backoff before failing.
  2. Manifest Probing: Probes skew-manifest.json on the origin to confirm that a newer deployment actually exists before reloading.
  3. Target Navigation Preservation: Uses location.assign(targetUrl) rather than location.reload() so the user lands on their intended destination route.
  4. Unsaved Work Protection: Detects dirty form state and avoids interrupting active user inputs.

Setup ​

ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideSkewRecovery } from '@braidlabs/angular-router';
import { BUILD_ID, BUILT_AT } from './build-id'; // Generated by @braidlabs/build
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideSkewRecovery({
      identity: { buildId: BUILD_ID, builtAt: BUILT_AT },
      manifestUrl: '/skew-manifest.json',
      maxRecoveries: 1,
      respectUnsavedWork: true,
    }),
  ],
};

Wrapping Lazy Routes ​

Wrap your dynamic import() calls with lazy():

ts
import { Routes } from '@angular/router';
import { lazy } from '@braidlabs/angular-router';

export const routes: Routes = [
  {
    path: 'portfolio',
    loadChildren: lazy('portfolio.routes', () => import('./portfolio/portfolio.routes')),
  },
];

Unsaved Work Protection ​

ts
import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { trackUnsavedWork } from '@braidlabs/angular-router';

@Component({ ... })
export class EditorComponent {
  form = new FormGroup({ title: new FormControl('') });

  constructor() {
    // Prevents automatic reloads while the form is dirty
    trackUnsavedWork(() => this.form.dirty);
  }
}