Search code examples
angularperformancenode-modulesangular-universalbrowser-api

Angular SSR - using performance.now() in both browser and server


I want to set some performance marks and measures in my Angular components to measure how long selected components take to process and render. They work fine when running the app in "client mode", but as soon as I run the app in SSR mode, I get "performance" is undefined.

ReferenceError: performance is not defined

I tried importing it from nodes 'perf_hooks' internal module, but then I get unknown module 'perf_hooks' when called from app.component.ts.
https://github.com/buggy1985/angular-ssr-performance/blob/HEAD/src/app/app.component.ts#L17

Cannot find module 'perf_hooks' or its corresponding type declaration

If I use performance.now() in server.ts it seems to be working. https://github.com/buggy1985/angular-ssr-performance/blob/HEAD/server.ts#L13

Can I pass the performance class from server.ts to the component? And for browser to fall back to window.performance? Or what am I doing wrong?


Solution

  • I finally managed to solve it by providing the correct performance api depending on the platform.

    Here is the full commit with my changes: https://github.com/buggy1985/angular-ssr-performance/commit/39aa08489e589172fa9bce6f1f5588f5eb962337

    I basically created a new provider, that injects the imported performance from perf_hooks in server.ts

    import { performance } from 'perf_hooks';
    export const PERFORMANCE_API = new InjectionToken('performance-api');
    ...
    
    @NgModule({
      providers: [
        { provide: PERFORMANCE_API, useValue: performance },
      ],
    }
    

    and injects windows.performance in app.browser.module

    providers: [
      { provide: PERFORMANCE_API, useValue: window.performance },
    ],
    

    In app.component.ts, instead of using performance directly, you have to inject it in the constructor and then use it as this.performance.

    constructor(@Inject(PERFORMANCE_API) private performance) {
        console.log(this.performance.now());
    }