7

I am trying to lazy load NgModule from a library. I have a ng app, which contains some libraries (projects). This libraries are reused in some other projects. The problem is i can't find a solution, that would work with both jit and aot, and compiled/not compiled library.

file structure is like this

app
-projects
--lib
---(lib files)
-src
--(app files)

AppModule has routing, which looks like this

const routes: Routes = [
    {
        path: 'eager',
        children: [
            {
                path: '',
                component: LibComponent // component imported from lib
            },
            {
                path: 'lazy',
                loadChildren: 'lib/src/lib/lazy/lazy.module#LazyModule' // module i want to load lazily
            }
        ]
    }
];

if i use it like this, i get runtime error when trying to navigate to lazy route in jit (aot works correctly): ERROR Error: Uncaught (in promise): TypeError: undefined is not a function TypeError: undefined is not a function

this comment https://github.com/angular/angular-cli/issues/9488#issuecomment-370065452 suggests not to include LazyModule to any barrel files, but if i exclude it from public_api of library i get build error:

ERROR in ./projects/lib/src/lib/lazy/lazy.module.ts
Module build failed (from ./node_modules/@ngtools/webpack/src/index.js):
Error: C:\projects\lazy_minimal\lazy-minimal\projects\lib\src\lib\lazy\lazy.module.ts is missing from the TypeSc
ript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
    at AngularCompilerPlugin.getCompiledFile (C:\projects\lazy_minimal\lazy-minimal\node_modules\@ngtools\webpac
k\src\angular_compiler_plugin.js:752:23)
    at plugin.done.then (C:\projects\lazy_minimal\lazy-minimal\node_modules\@ngtools\webpack\src\loader.js:41:31
)
    at process._tickCallback (internal/process/next_tick.js:68:7)

is there any way to make it work for both aot and jit?

5
  • it is still impossible without wrapper module: github.com/angular/angular-cli/issues/… Commented Apr 12, 2019 at 9:21
  • Did you try not to use barrel files at all ? I have had weird behaviour occur when using barrel files and lazy loaded modules in the past. Commented Apr 12, 2019 at 9:23
  • trick with wrapper seems to lazy load only wrapper module, when module from library i need to be lazy is included in main bundle Commented Apr 12, 2019 at 9:34
  • barrel file is public api in root of the library, it is specified as entry point for ng-package.json. how can i build library avoiding it? Commented Apr 12, 2019 at 9:35
  • check the updated post @ADAmelin Commented Apr 29, 2019 at 6:14

1 Answer 1

8

There is an issue in Angular-CLI about loading compiled library in node_modules in lazy loading way. The following is the workaround suggested by Alan Agius

This thread was opened a while ago. Having so comments makes it hard for people to find information in anything but the latest comments. But on the other hand I don't think most people would go through all of the comments anyway. New users that see this thread mostly read the first and latest comments and lose things said in between.

So for the reasons stated above (high volume of comments, hidden comments, hard to report and inform people) I'm locking this issue to prevent this comment from being lost as new comments come in.

Thank you to everyone that reported and helped diagnose the problems and provided workarounds.

Our recommended approach to lazy load a library within an angular workspace or node modules, is to use a proxy/wrapper module. With this approach lazy loading will works in both JIT and AOT mode. There are other solutions that work solely in AOT mode such as tsconfig imports however for a better development experience we don't encourage this.

Below find an example of the recommended approach;

lazy/lazy.module.ts

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { LibModule, LazyComponent } from 'my-lib';

@NgModule({
  imports: [
    LibModule,
    RouterModule.forChild([
      { path: '', component: LazyComponent, pathMatch: 'full' }
    ])
  ]
})
export class LazyModule { }

app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
  ],
  imports: [
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full'},
      { path: 'lazy', loadChildren: './lazy/lazy.module#LazyModule'},
    ]),
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
Sign up to request clarification or add additional context in comments.

3 Comments

Now receive Error: Angular JIT compilation failed: '@angular/compiler' not loaded! when doing this in Angular9, FYI
Lazy loading in angular 9 is a lot different with angular 7 johnpapa.net/angular-9-lazy-loading-components
Turned out it's an issue with ivy and symlinks. A temporary fileset gets created but not in time for the server to pick it up and outside the filewatch. Seems to work when stopping the server and running again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.