Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions examples/angular/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/angular",
"index": "src/index.html",
Expand Down Expand Up @@ -61,7 +61,7 @@
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "angular:build:production"
Expand All @@ -73,10 +73,10 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n"
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
Expand All @@ -100,5 +100,31 @@
},
"cli": {
"analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}
28 changes: 14 additions & 14 deletions examples/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~19.2.0",
"@angular/common": "~19.2.0",
"@angular/compiler": "~19.2.0",
"@angular/core": "~19.2.0",
"@angular/forms": "~19.2.0",
"@angular/platform-browser": "~19.2.0",
"@angular/platform-browser-dynamic": "~19.2.0",
"@angular/platform-server": "~19.2.0",
"@angular/router": "~19.2.0",
"@angular/ssr": "~19.2.0",
"@angular/animations": "~21.2.4",
"@angular/common": "~21.2.4",
"@angular/compiler": "~21.2.4",
"@angular/core": "~21.2.4",
"@angular/forms": "~21.2.4",
"@angular/platform-browser": "~21.2.4",
"@angular/platform-browser-dynamic": "~21.2.4",
"@angular/platform-server": "~21.2.4",
"@angular/router": "~21.2.4",
"@angular/ssr": "^21.2.2",
"express": "^4.18.2",
"rollbar": "file:../rollbar.tgz",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~19.2.0",
"@angular/cli": "~19.2.0",
"@angular/compiler-cli": "~19.2.0",
"@angular/build": "^21.2.2",
"@angular/cli": "~21.2.2",
"@angular/compiler-cli": "~21.2.4",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
"@types/node": "^18.18.0",
Expand All @@ -40,6 +40,6 @@
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.6.2"
"typescript": "~5.9.3"
}
}
2 changes: 1 addition & 1 deletion examples/angular/src/app/app.config.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { provideServerRendering } from '@angular/ssr';
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';

const serverConfig: ApplicationConfig = {
Expand Down
12 changes: 2 additions & 10 deletions examples/angular/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
// src/app/app.config.ts
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import type { ApplicationConfig } from '@angular/core';
import { ErrorHandler } from '@angular/core';

import { RollbarService, RollbarErrorHandler } from './rollbar.errorhandler';
import { RollbarFactory } from './rollbar.config';
import { RollbarErrorHandler } from './rollbar.errorhandler';

export const appConfig: ApplicationConfig = {
providers: [
// The usual providers for a browser app
importProvidersFrom(BrowserModule),

// Provide the Rollbar injection token with the Rollbar factory
{ provide: RollbarService, useFactory: RollbarFactory },

// Override Angular’s default ErrorHandler
{ provide: ErrorHandler, useClass: RollbarErrorHandler },
],
Expand Down
3 changes: 2 additions & 1 deletion examples/angular/src/app/rollbar.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const rollbarConfig = {
},
};

export function RollbarFactory() {
export function createRollbar() {
return new Rollbar(rollbarConfig);
}

36 changes: 25 additions & 11 deletions examples/angular/src/app/rollbar.errorhandler.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
// src/app/rollbar.errorhandler.ts
import { ErrorHandler, inject, Injectable, InjectionToken } from '@angular/core';
import Rollbar from 'rollbar';

// InjectionToken for providing a Rollbar instance
export const RollbarService = new InjectionToken<Rollbar>('rollbar');
import { type ErrorHandler, inject, Injectable, NgZone } from '@angular/core';
import { defer, map, shareReplay } from 'rxjs';

@Injectable()
export class RollbarErrorHandler implements ErrorHandler {
// Option 1: Use `inject` (if you’re using Angular v14+)
private rollbar = inject(RollbarService);
private ngZone = inject(NgZone);

// Lazily load Rollbar on first error to keep it out of the initial bundle.
// `defer` ensures the dynamic import is not triggered until the first
// subscription. `shareReplay` caches the result so subsequent errors reuse
// the same Rollbar instance without re-importing or re-initializing.
private rollbar$ = defer(() => import('./rollbar.config')).pipe(
map(({ createRollbar }) => createRollbar()),
shareReplay({ bufferSize: 1, refCount: false })
);

handleError(error: any): void {
// Send error to Rollbar
this.rollbar.error(error);
// Optionally rethrow the error if you want default logging
throw error;
// Run outside Angular's zone so that the dynamic import and Rollbar's
// internal async work do not trigger unnecessary change detection cycles.
this.ngZone.runOutsideAngular(() => {
this.rollbar$.subscribe(rollbar => {
// Send error to Rollbar
rollbar.error(error);
// Rollbar load failures are intentionally ignored — error reporting
// is best-effort and should never affect the application's behaviour.
});
});
// Log to the console so errors remain visible during development even
// if Rollbar has not finished loading yet.
console.error(error);
}
}
16 changes: 14 additions & 2 deletions examples/angular/src/main.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { bootstrapApplication, type BootstrapContext } from '@angular/platform-browser';
import { provideZoneChangeDetection } from '@angular/core';
import {
bootstrapApplication,
type BootstrapContext,
} from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';

const bootstrap = (context?: BootstrapContext) => bootstrapApplication(AppComponent, config, context);
const bootstrap = (context?: BootstrapContext) =>
bootstrapApplication(
AppComponent,
{
...config,
providers: [provideZoneChangeDetection(), ...config.providers],
},
context,
);

export default bootstrap;
7 changes: 5 additions & 2 deletions examples/angular/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { provideZoneChangeDetection } from '@angular/core';
// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
bootstrapApplication(AppComponent, {
...appConfig,
providers: [provideZoneChangeDetection(), ...appConfig.providers],
}).catch((err) => console.error(err));
Loading