Ionic-framework: bug: SSR, Flickering when ssr page is replaced

Created on 28 May 2020  路  8Comments  路  Source: ionic-team/ionic-framework

Bug Report

Ionic version:
[x] 5.0.5

Current behavior:
When the app switches from server side rendered to client side rendered version, there is is a blank screen shown, resulting in a flickering on fast-loading devices.

This is not the case when using angular universal without ionic.

Expected behavior:
The user should not recognize the switch, as with original angular universal apps.

Steps to reproduce:
Create Angular SSR application.
Add Ionic.

Example
To see it more clearly, check this example (25s video) where I used a slow network speed.
Between "IsServer -> IsBrowser", a blank page appears.

ionic-ssr-flicker

A sample application via GitHub
Github Ionic-SSR-Flickering
Github Angular-SSR-No-Flickering

The live examples can be compared here:
Live Ionic SSR example
Live Angular SSR example

I opened a new ticket because my existing ticket was closed as it was initially missing an example. #21245

angular

Most helpful comment

I'm experiencing the same issue with the following Ionic version:

Ionic info:

Ionic:

   Ionic CLI                     : 6.11.8 (/Users/agustin/.npm-global/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.3.3
   @angular-devkit/build-angular : 0.1001.2
   @angular-devkit/schematics    : 10.1.2
   @angular/cli                  : 10.1.2
   @ionic/angular-toolkit        : 2.3.3

Capacitor:

   Capacitor CLI   : 2.4.1
   @capacitor/core : 2.4.1

Utility:

   cordova-res (update available: 0.15.1) : 0.11.0
   native-run                             : not installed

System:

   NodeJS : v12.14.1 (/usr/local/bin/node)
   npm    : 6.14.8
   OS     : macOS Catalina

I've invested quite some time trying to understand what was really going on behind this bug in the hopes of adding value to this conversation and maybe get us a step closer to fixing this issue.

Debugging the main.ts file, I identified the following:

// 1 - SSR version of the app loaded [content OK]

document.addEventListener('DOMContentLoaded', () => {
  // 2 - DOMContentLoaded triggers [content OK]

  setTimeout(() => {
    // 3 - Before AppModule get鈥檚 bootstrapped [First flick (partial)]
  }, 100);

  platformBrowserDynamic().bootstrapModule(AppModule)
  .then(() => {
    // 4 - Immediately after the AppModule get鈥檚 bootstrapped [Second flick (full)]

    setTimeout(() => {
      // 5 - Some instants after AppModule get鈥檚 bootstrapped [content OK]
    }, 300);
  })
  .catch(err => console.log(err));
});
  1. Load SSR version of the app (comes from the server with .hydrated classes). Everything looks OK.

  2. DOMContentLoaded triggers.

  3. First flick (partial): Before AppModule get鈥檚 bootstrapped on the browser, it seems to be an issue with the transition from the emulated shadow dom from the SSR and the actual shadow dom when transitioning to the browser. All the content inside shadow dom disappears (and that鈥檚 what causes the blank screen flick). I suspect it has something to do with the shadow dom, because if I put some content (a heading) outside the shadow dom, it doesn鈥檛 disappear.

I think this first one is a partial flick because all the content outside the shadow dom seems to be intact.

  1. Second flick (full): Immediately after the AppModule get鈥檚 bootstrapped, some components lose the hydrated class (ie: <ion-page>). This causes everything inside those components to be hidden.

  2. Some instants (couple milliseconds) after AppModule get鈥檚 bootstrapped, all hydrated classes are properly set again, causing the content to be visible again.


_In the process I have discarded some of the hypothesis I found around the web. In my experience:_

  • Avoiding http requests when transitioning back to the browser from the SSR make no difference in the flick.
  • Properly using TransferState (both BrowserTransferStateModule and ServerTransferStateModule) make no difference in the flick.
  • Implementing advanced use cases for the TransferState (ie: Storing http requests made on the server and getting that data when transitioning to the browser to avoid duplicate requests) make no difference in the flick.
  • Going a step further and configuring angular/preboot make no difference in the flick.

Note: In the current production version of my app I have implemented all the previously mentioned solutions and the flick is still happening.

I'm basically sharing my experience so others don't waste time (like I did) trying solutions that are dead ends.

Hope the time I invested analyzing the situation helps move this forward.

All 8 comments

Thank you for the detailed demo! After talking with the team a bit, this will likely require a refactor in how our components are loaded to address this. At least from looking at it quickly..

Just to add why this really is a problem for anyone using SSR:

The advantage of SSR is that the user thinks at the _First Meaningful Paint_ that the application is fully ready. This is typically at <1 second.

Now here he clearly sees the loading process until the _Time to Interactive_ is finished, which is typically 3x the first value.

So the visual performance is now reduced to a 1/3 of what it could be, making SSR Ionic applications slower than not using SSR at all.

The example above is super small, making everything very fast, but for big applications it is very recognizeable.

thank you @KevinBassaDevelopment for your demo ,I meet the same issue
If the page has a ajax request will see the flickering ,wish to fix this issue

I tested in an Ionic Sidemenu starter app version 5 with Angular 9 ivy, it doesn't work correctly in menu side when javascript is disabled. The menu side is not appeared.

Still having this issue on ionic 5.3.1/ng 10.1, has there been any progress?

ionic info

Ionic:

   Ionic CLI                     : 6.11.0 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.3.1
   @angular-devkit/build-angular : 0.1000.7
   @angular-devkit/schematics    : 10.0.7
   @angular/cli                  : 10.1.0
   @ionic/angular-toolkit        : 2.3.2

Same, we using ionic's angular-server technics to build our app, who using stencil as a design-system through Angular. It's the same case, server rendering is good and appear in window, but after we have a glitch when Angular load the app.

Maybe anyone can help with this topic?

I'm experiencing the same issue with the following Ionic version:

Ionic info:

Ionic:

   Ionic CLI                     : 6.11.8 (/Users/agustin/.npm-global/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.3.3
   @angular-devkit/build-angular : 0.1001.2
   @angular-devkit/schematics    : 10.1.2
   @angular/cli                  : 10.1.2
   @ionic/angular-toolkit        : 2.3.3

Capacitor:

   Capacitor CLI   : 2.4.1
   @capacitor/core : 2.4.1

Utility:

   cordova-res (update available: 0.15.1) : 0.11.0
   native-run                             : not installed

System:

   NodeJS : v12.14.1 (/usr/local/bin/node)
   npm    : 6.14.8
   OS     : macOS Catalina

I've invested quite some time trying to understand what was really going on behind this bug in the hopes of adding value to this conversation and maybe get us a step closer to fixing this issue.

Debugging the main.ts file, I identified the following:

// 1 - SSR version of the app loaded [content OK]

document.addEventListener('DOMContentLoaded', () => {
  // 2 - DOMContentLoaded triggers [content OK]

  setTimeout(() => {
    // 3 - Before AppModule get鈥檚 bootstrapped [First flick (partial)]
  }, 100);

  platformBrowserDynamic().bootstrapModule(AppModule)
  .then(() => {
    // 4 - Immediately after the AppModule get鈥檚 bootstrapped [Second flick (full)]

    setTimeout(() => {
      // 5 - Some instants after AppModule get鈥檚 bootstrapped [content OK]
    }, 300);
  })
  .catch(err => console.log(err));
});
  1. Load SSR version of the app (comes from the server with .hydrated classes). Everything looks OK.

  2. DOMContentLoaded triggers.

  3. First flick (partial): Before AppModule get鈥檚 bootstrapped on the browser, it seems to be an issue with the transition from the emulated shadow dom from the SSR and the actual shadow dom when transitioning to the browser. All the content inside shadow dom disappears (and that鈥檚 what causes the blank screen flick). I suspect it has something to do with the shadow dom, because if I put some content (a heading) outside the shadow dom, it doesn鈥檛 disappear.

I think this first one is a partial flick because all the content outside the shadow dom seems to be intact.

  1. Second flick (full): Immediately after the AppModule get鈥檚 bootstrapped, some components lose the hydrated class (ie: <ion-page>). This causes everything inside those components to be hidden.

  2. Some instants (couple milliseconds) after AppModule get鈥檚 bootstrapped, all hydrated classes are properly set again, causing the content to be visible again.


_In the process I have discarded some of the hypothesis I found around the web. In my experience:_

  • Avoiding http requests when transitioning back to the browser from the SSR make no difference in the flick.
  • Properly using TransferState (both BrowserTransferStateModule and ServerTransferStateModule) make no difference in the flick.
  • Implementing advanced use cases for the TransferState (ie: Storing http requests made on the server and getting that data when transitioning to the browser to avoid duplicate requests) make no difference in the flick.
  • Going a step further and configuring angular/preboot make no difference in the flick.

Note: In the current production version of my app I have implemented all the previously mentioned solutions and the flick is still happening.

I'm basically sharing my experience so others don't waste time (like I did) trying solutions that are dead ends.

Hope the time I invested analyzing the situation helps move this forward.

Has anyone come up with an idea yet on how to fix this? How exactly would an ionic component have to be loaded differently to get rid of this flicker?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MrBokeh picture MrBokeh  路  3Comments

danbucholtz picture danbucholtz  路  3Comments

alexbainbridge picture alexbainbridge  路  3Comments

daveshirman picture daveshirman  路  3Comments

gio82 picture gio82  路  3Comments