Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

server app instance not removed from DOM after client bootstraps app #111

Open
4 of 8 tasks
mohamedaarab1994 opened this issue Jan 21, 2020 · 6 comments
Open
4 of 8 tasks

Comments

@mohamedaarab1994
Copy link

Note: for support questions, please use the Universal Slack Channcel or https://gitter.im/angular/universal

  • I'm submitting a ...
  • bug report
  • feature request
  • Which parts of preboot are affected by this issue?
  • server side
  • client side
  • inline
  • build process
  • docs
  • tests
  • Do you want to request a feature or report a bug?
    Question/bug

  • What is the current behavior?
    I'm having an issue with the application not working with buffer set to true. (works if I turn off buffer). What happens is that the visible app-root is completely unusable while the hidden one with display: none works correctly. The pre-rendered version should be removed or hidden from the DOM once the client finishes bootstrapping, but in this case it doesn't happen.

https://i.imgur.com/S8n4ctp.png

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem by creating a github repo.
    I only added PrebootModule.withConfig({ appRoot: 'app-root' }), to app.module and
    applied a fix for the flickering issue mentioned Big FOUC as server side styles removed before the switch to client side #75 (comment)

  • What is the expected behavior?
    It should remove the pre-rendered selector from the DOM after the client is finished bootstrapping.

  • What is the motivation / use case for changing the behavior?
    I need help getting this fixed

  • Please tell us about your environment:

  • Browser: Chrome 79
  • Language: Typescript
  • OS: Windows
  • Platform: NodeJs
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)
@a-syde
Copy link

a-syde commented Jul 4, 2020

@mohamedaarab1994 Have you got any updates on this?
Angular doesn't bootstrap client side at all, therefore there is no JS code at all. Only links work.
Preboot works as it should when you run:
"dev:ssr": "ng run frontend:serve-ssr"
It is really frustrating 😞
image

@akshata456
Copy link

akshata456 commented Sep 2, 2020

@CaerusKaru any update on this? I'm facing the same issue in angular 9

@shyamal890
Copy link

I am facing the same issue, can you please update us on this please.

@ocombe
Copy link

ocombe commented Sep 10, 2020

I had the same issue until I realized that appId and appRoot need to be the same:

In my AppModule:

BrowserModule.withServerTransition({ appId: 'app-root' }),
PrebootModule.withConfig({ appRoot: 'app-root' })

After that, everything worked like a charm.

@akshata456
Copy link

I had the same issue until I realized that appId and appRoot need to be the same:

In my AppModule:

BrowserModule.withServerTransition({ appId: 'app-root' }),
PrebootModule.withConfig({ appRoot: 'app-root' })

After that, everything worked like a charm.

It works for me .Thanks.

@ocombe
Copy link

ocombe commented Sep 21, 2020

Ok another reason why this might fail: preboot uses the observable appRef.isStable, which might never get stable because according to the documentation:

the application will never be stable if you start any kind of recurrent asynchronous task when the application starts (for example for a polling process, started with a setInterval, a setTimeout or using RxJS operators like interval);

These asynchronous tasks can be in your code (setTimeout, setInterval, or interval operator), or in any of your external libraries... making it very hard to debug.

A solution is to manually do the cleanup:

  • Inject EventReplayer in your code
  • call this.eventReplayer.replayAll();

This will make the replay of events, and then the cleanup of the server side application. You will be responsible for making sure that your app is loaded, otherwise you'll see a nice FOC when it switches from one app to the other...
If you're not replaying events, you can directly call this.eventReplayer.cleanup();

To help you detect pending async events such as setInterval, you can use the following code in your main.ts file:

document.addEventListener('DOMContentLoaded', () => {
  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .then(moduleInstance => {
      // Ensure Angular destroys itself on hot reloads.
      if (window['ngRef']) {
        window['ngRef'].destroy();
      }
      window['ngRef'] = moduleInstance;
      const ngZone = moduleInstance.injector.get(NgZone);
      setInterval(() => {
        const taskTrackingZone = (<any>ngZone)._inner.getZoneWith('TaskTrackingZone');
        if (!taskTrackingZone) {
          throw new Error(
            `'TaskTrackingZone' zone not found! Have you loaded 'node_modules/zone.js/dist/task-tracking.js'?`
          );
        }
        let tasks: any[] = taskTrackingZone._properties.TaskTrackingZone.getTasksFor('macroTask');
        tasks = clone(tasks);
        if (size(tasks) > 0) {
          console.log('ZONE pending tasks', tasks);
        }
      }, 1000);
      // Otherwise, log the boot error
    })
    .catch((error: string) => {
      /* tslint:disable-next-line */
      console.error(error);
    });
});

And add import 'zone.js/dist/task-tracking'; in your polyfill.ts file

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants