Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy load of editor in module #628

Closed
SitecHQ opened this issue May 18, 2021 · 6 comments
Closed

Lazy load of editor in module #628

SitecHQ opened this issue May 18, 2021 · 6 comments

Comments

@SitecHQ
Copy link

SitecHQ commented May 18, 2021

When I add CodeEditorModule.forRoot() in my app.module.ts and CodeEditorModule.forChild() in my lazyload.module.ts, the editor is loaded after startup even if the lazy load module is not.

Editor files from content delivery network should loaded only if lazy loaded modul loaded

@CharlieGreenman
Copy link

If you end up following the instructions for allowing offline access, it will partially sidestep this problem. Takes me 45ms to load ngstack/code-editor locally.

@mfp22
Copy link

mfp22 commented Jun 28, 2022

@CharlieGreenman has a pretty okay solution. It will request the JS bundle as an asset, so it happens concurrently I believe.

But I wanted to lazy-load the entire dependency. So I looked at the codebase here for a bit.

forRoot loads the editor by providing APP_INITIALIZER, which is a feature I wish Angular never gave developers. It's always getting in the way of code splitting. You can see the code here https://github.com/ngstack/code-editor/blob/master/projects/code-editor/src/lib/code-editor.module.ts#L36

However, I see the difficulty too, because if I inject the same service CodeEditorService in the first component that loads in the lazy-loaded route, the editor takes too long to load so the component doesn't have the editor working inside of it.

So this is the order that must happen:

  • The app must initialize first
  • Then forRoot() can be called to set things up
  • Then CodeEditorService.loadEditor can be called from a place that has access to the CodeEditorService provider
  • Then the component can be loaded

So my solution was to call forRoot in the lazy-loaded module, then in the root component of that module, I injected CodeEditorService from this library, which thankfully is exported. I had a property like this:

editorLoaded = (window as any).editorLoaded;

constructor(private codeEditorService: CodeEditorService) {
  (window as any).editorLoaded || this.codeEditorService.loadEditor().then(() => {
    (window as any).editorLoaded = this.editorLoaded = true;
  });
}

Then in the template I put a placeholder where the editor should be until it's loaded.

This was fine, but I wanted to pre-load it too. So I made this service instead:

@Injectable({ providedIn: 'root' })
export class EditorReadyService {
  ready$ = new BehaviorSubject(false);
}

Used it in the component like this:

editorReady$ = inject(EditorReadyService).ready$;

Then I re-exported it from the lazy-loaded module file. In the app.component.ts I put this in the constructor:

import('./lazy-loaded.module').then(m =>
      this.injector
        .get(m.CodeEditorService)
        .loadEditor()
        .then(() => this.injector.get(m.EditorReadyService).ready$.next(true)),
    );

I could access all of that here without having to load any of it up front thanks to providedInRoot.

As soon as the app is done loading, it fetches that lazy-loaded file. Pre-fetching and my app.component code both want it, so they share the request. The forRoot for the editor module runs first, then my app.component code that loads the editor. Then the component shows the editor.

The only problem is I get this console error 3 times:

main.js:1 ERROR TypeError: Cannot read properties of null (reading 'monaco')
    at x._next (778.js:1:5941)
    at x.__tryOrUnsub (main.js:1:447315)
    at x.next (main.js:1:446542)
    at J._next (main.js:1:445710)
    at J.next (main.js:1:445484)
    at U._subscribe (main.js:1:440439)
    at U._trySubscribe (main.js:1:441384)
    at U._trySubscribe (main.js:1:444087)
    at U.subscribe (main.js:1:441191)
    at new n (778.js:1:5914)

It never comes back and I haven't noticed anything wrong.

@CharlieGreenman
Copy link

cool, this is great! I'm going to dive deeper into this later on today

@CharlieGreenman
Copy link

For what it's worth, I ended up moving off this library and creating my own homegrown version. I found it ended up messing with the performance of the application too much

@mfp22
Copy link

mfp22 commented Nov 12, 2022

Nice. If you end up publishing it, I might use it. For now I consider my solution technical debt

@CharlieGreenman
Copy link

We will think about it. In the meantime, I sent you an email if interested

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

No branches or pull requests

4 participants