Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular universal flickering

I'm having a flicker while the website is loading. The HTML coming form the server is downloaded and then in the UI the view is rendered and there is a small flicker between the transition.

I managed to fix it by adding:

RouterModule.forRoot([ // ROUTES HERE ], { initialNavigation: 'enabled' })

But I wanted to know why it happend? Because of the lazy loading of the components? So we got a flicker between the transition while the UI (angular components) building the DOM? And let's say I had a 'light' component the flicker would be faster?

like image 678
John doe Avatar asked Apr 24 '18 09:04

John doe


People also ask

Why does my angular application flicker?

This can cause a very disruptive flickering effect in your application. Of course, making an additional request also adds a delay in form of latency to your application load time. It can be a significant factor if the angular application is loaded on mobile devices.

What is @Angular Universal and how to use it?

Angular Universal is an open-source project that extends the functionality of @angular/platform-server. The project makes server-side rendering possible in Angular. This article will discuss the issues and possible solutions we encountered while developing a real application with Angular Universal.

Is server-side rendering possible with Angular Universal?

The project makes server-side rendering possible in Angular. Another package Socket Engine is a framework-agnostic that theoretically allows any backend to be connected to an SSR server. This article will discuss the issues and possible solutions we encountered while developing a real application with Angular Universal and Express.

Why does my website flicker when downloading?

Once, when the server is rendering the page and another time when the application is bootstrapped. This behavior does not only produce unnecessary server load but also causes your application to reload and re-evaluate the page and the downloaded content. This can cause a very disruptive flickering effect in your application.


2 Answers

Scroll down to the bold section for the answer, read all of it for an explanation as to what is happening.

A very simplified explanation as to what is happening:

1.) A user goes to your application (or refreshes)

2.) The server builds the html in the server

3.) It gets sent to the browser where the user sees it

4.) The angular applications "re-creates" the application (as if it was a regular non-universal application)

5.) The user sees a flash when this change occurs.

// You can see this by adding:
// You should see a console log in the server
// `Running on the server with appId=my-app-id`
// and then you'll see in the browser console something like
// `Running on the browser with appId=my-app-id`
export class AppModule {
  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
    @Inject(APP_ID) private appId: string) {
    const platform = isPlatformBrowser(this.platformId) ?
      'in the browser' : 'on the server';
    console.log(`Running ${platform} with appId=${this.appId}`);
  }
}

This is intentional as you want bots to be able to pick up meta tags, etc.

In order to remove the flash what you could do is transfer state from the server to the client:

You will need to add this to your imports in your AppServerModule

ServerTransferStateModule

And you'll need to add this to your AppModule:

BrowserTransferStateModule

update the main.ts file to listen for DOMContentLoaded before bootstraping the browser app:

document.addEventListener('DOMContentLoaded', () => { platformBrowserDynamic().bootstrapModule(AppModule) })

and then an example on how you transfer state:

import { tap, startWith } from 'rxjs/operators';
import { TransferState, makeStateKey } from '@angular/platform-browser';

const ANIMAL_KEY = makeStateKey<any>('animal');

// omitted ...

    ngOnInit() {
        const id = this.route.snapshot.paramMap.get('name').toLowerCase();
        this.animal$ = this.ssrFirestoreDoc(`animals/${id}`);
    }

    ssrFirestoreDoc(path: string) {
        const exists = this.state.get(ANIMAL_KEY, {} as any);
        return this.afs.doc<any>(path).valueChanges().pipe(
            tap(animal => {
                this.state.set(ANIMAL_KEY, animal)
                this.seo.generateTags({
                title: animal.name,
                description: animal.bio,
                image: animal.imgURL
            });
        }),
        startWith(exists))
    }

I got all of this from: Angular Universal with Firebase and Code and a more thorough explanation

like image 108
DonDaniel Avatar answered Sep 30 '22 06:09

DonDaniel


I ran into this issue as well, but sadly for me the initialNavigatin didn't help. But, anyway, you can find details of "why" this happens at this github issue: https://github.com/angular/angular/issues/15716

Confirmed. In my app all the routes are lazy loaded, using css with default ViewEncapsulation and angular starts removing the tags with the ng-transition in browser, this process takes like a second. After the bootstrap finishes, it adds the styles back. Here's how it looks like http://take.ms/1wizt

Hope this helps you understand, i'm still trying to fix this problem on my app

like image 32
Michelle Colin Avatar answered Sep 30 '22 07:09

Michelle Colin