SSR - Angular Universal 9 loading my root twice and hanging

Viewed 705

I'm trying to find why my code is binding root two times using Angular 9 SSR.

I tried eventReplayer.replayAll() trick but I'm still stuck, I noticed when I'm scrolling into the page finally I'm getting the the proper root loaded perfectly and the other one removed (ng-non-bindable), so I removed PrebootModule just to narrow the issue and I got one root in my dom but the application won't run properly.

enter image description here

app.component.ts

BrowserModule.withServerTransition({appId: 'dcaa'}),
PrebootModule.withConfig({appRoot: 'dcaa-root'}),
.
.
.
{
      provide: APP_INITIALIZER,
      useFactory: function (document: HTMLDocument, platformId: Object): Function {
        return () => {
          if (isPlatformBrowser(platformId)) {
            const dom = getDOM();
            const styles: any[] = Array.prototype.slice.apply(document.querySelectorAll('style[ng-transition]'));
            styles.forEach(el => {
              // Remove ng-transition attribute to prevent Angular appInitializerFactory
              // to remove server styles before preboot complete
              el.removeAttribute('ng-transition');
            });
            document.addEventListener('PrebootComplete', () => {
              // After preboot complete, remove the server scripts
              setTimeout(() => styles.forEach(el => dom.remove(el)));
            });
          }
        };
      },
      deps: [DOCUMENT, PLATFORM_ID],
      multi: true
    }

app.routes.ts

imports: [RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'disabled',
    relativeLinkResolution: 'corrected',
    preloadingStrategy: PreloadAllModules,
    initialNavigation: 'enabled'
  }),

app.server.module.ts

imports: [
    AppModule,
    ServerModule,
    ServerTransferStateModule,
    FlexLayoutServerModule
  ],

main.ts

document.addEventListener('DOMContentLoaded', () => {
  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
});
1 Answers

I had the same issue with preboot when I was was trying to manipulate the DOM during ngAfterViewInit on the browser side, this cause PrebootComplete to not fire properly because the DOM has changed.

The fix is to inject EventReplayer in your component:

import { EventReplayer } from 'preboot';
constructor(
    @Inject(PLATFORM_ID) private platformId: any,
    private replayer: EventReplayer
  )

And then replay preboot events:

ngAfterViewInit() {
    if (isPlatformBrowser(this.platformId)) {
      // ....
      // Manipulate your DOM here 
      // ....

      this.replayer.replayAll()      
    }
  }
Related