Skip to content

Let 'lazyModules' option support modules from outside root in AOT mode #12859

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

Closed
woppa684 opened this issue Nov 3, 2018 · 12 comments
Closed

Comments

@woppa684
Copy link

woppa684 commented Nov 3, 2018

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [X] feature request

Command (mark with an x)

- [ ] new
- [X] build
- [X] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Versions

Angular CLI: 7.0.3
Node: 8.11.3
OS: win32 x64
Angular: 7.0.1
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.10.3
@angular-devkit/build-angular      0.10.3
@angular-devkit/build-ng-packagr   0.10.3
@angular-devkit/build-optimizer    0.10.3
@angular-devkit/build-webpack      0.10.3
@angular-devkit/core               7.0.3
@angular-devkit/schematics         7.0.3
@angular/cli                       7.0.3
@ngtools/json-schema               1.1.0
@ngtools/webpack                   7.0.3
@schematics/angular                7.0.3
@schematics/update                 0.10.3
ng-packagr                         4.4.0
rxjs                               6.3.3
typescript                         3.1.4
webpack                            4.19.1

Repro steps

The addition of the 'lazyModules' option was something that people have been asking for for quite some time (to not "abuse" to router to create chunks). Unfortunately the lazyModules option still requires the module to be in the src folder, and therefore it is not possible to lazy load a module from a component library or an external dependency in node_modules. At the moment te only way to achieve this is to create another module that is somewhere under the src folder and imports the external module.

This works:

lazyModules: ["src/app/proxies/sample-lib.proxy"]
import { NgModule } from '@angular/core';
import { SampleLibModule, SampleLibComponent } from 'sample-lib';

@NgModule({
    imports: [SampleLibModule],
    entryComponents: [SampleLibComponent]
})
export class SampleLibProxyModule {

}

and this doesn't

lazyModules: ["projects/sample-lib/sample-lib.module"]

The log given by the failure

It curently fails with something like

ERROR in ./src/$$_lazy_route_resource lazy namespace object
Module not found: Error: Can't resolve '<mypath>/projects/sample-lib/src/lib/sample-lib.module.ngfactory.js' in <mypath>\src\$$_lazy_route_resource'

Desired functionality

lazyModules also supports including modules from node_modules and projects folders.

@alan-agius4
Copy link
Collaborator

To lazy load a library you need to use the library name to import, the one in your package.json, rather than the relative path, similar to how you import a library when using the import syntax.

For example

lazyModules: [
'sample-lib/sample-lib.module#ModuleAModule'
]

See here for more context:
#5986

@woppa684
Copy link
Author

woppa684 commented Nov 4, 2018

Yes, so I had tried a few different versions already....

The library I want to lazy load is actually located in projects/mylibs/samples/sample-lib and its name in the package.json is @mylibs/samples/sample-lib. I've tried the following strings in lazyModules:

mylibs/samples/sample-lib/sample-lib.module
mylibs/samples/sample-lib/sample-lib.module#SampleLibModule
@mylibs/samples/sample-lib/sample-lib.module
@mylibs/samples/sample-lib/sample-lib.module#SampleLibModule
mylibs/samples/sample-lib/lib/sample-lib.module
mylibs/samples/sample-lib/lib/sample-lib.module#SampleLibModule
@mylibs/samples/sample-lib/lib/sample-lib.module
@mylibs/samples/sample-lib/lib/sample-lib.module#SampleLibModule
mylibs/samples/sample-lib/src/lib/sample-lib.module
mylibs/samples/sample-lib/src/lib/sample-lib.module#SampleLibModule
@mylibs/samples/sample-lib/src/lib/sample-lib.module
@mylibs/samples/sample-lib/src/lib/sample-lib.module#SampleLibModule

Apart from that, also the version I posted above (with the proxy module) doesn't work when I specify it with the module class name and a # at the end. Everything returns an error like

ERROR in ./src/$$_lazy_route_resource lazy namespace object
Module not found: Error: Can't resolve 'D:/Repos/Test/mylibs/samples/sample-lib/sample-lib.module#SampleLibModule.ngfactory.js' in 'D:\Repos\Test\src\$$_lazy_route_resource'

The implementing PR #9515 also does't put the # and the module class name in the lazyModules option by the way. In the same PR it is said that the paths are relative to the "root" setting, which by default is "" as opposed to sourceRoot, which by default is "src". That's obviously why the "proxy" is working with src/app/... and without the #. (see this PR angular/devkit#755, where the path in the test was fixed to also include the "src" part).

When I looked in the code I could not find any special handling so I still expect this to be a feature request (or a bug if it should have worked).

@woppa684
Copy link
Author

woppa684 commented Nov 4, 2018

What might be worth noting is that I'm compiling with AOT and that for example specifying something like the following in JIT mode DOES work!

lazyModules: [
    "dist/mylibs/samples/sample-lib"
]

So it might be related to #8142 and #6373 (but that seems to be specifically about lazy loading in the router of a library)

@woppa684 woppa684 changed the title Let 'lazyModules' option support modules from outside root (e.g. node_modules or projects) Let 'lazyModules' option support modules from outside root in AOT mode Nov 4, 2018
@totkeks
Copy link

totkeks commented Nov 10, 2018

I have the same problem and built a super small angular 7 repository to reproduce it: https://github.com/totkeks/angular-bugs/tree/bug/lazy-route-no-factory
Also includes a workaround, which is basically telling typescript to import the library module, but not doing anything with it, resulting in the ngfactory and chunk being generated.

My analysis so far is, that the ngfactory is not being built by the angular (typescript) compiler. Because the error message comes from the webpack bundler, which is correctly identifying the lazy loaded route and tries to load the ngfactory and bundle it into a separate chunk to be lazy loaded in the application at a later point.

Unfortunately digging into angular/cli and angular/compiler was not very successful for me. If anyone could help me set up the breakpoints in vscode with the typescript sources of the angular compiler, then I could continue digging.

@sengirab
Copy link

sengirab commented Dec 1, 2018

I'm using "@nrwl/nx": "7.1.1 for our folder structure and management.

Folder structure is:
49329013-9980c080-f579-11e8-82bb-f9dadfe94f77

I'm thinking that this issue is related, since i'm getting the same error after updating @angular-devkit/build-angular which is using a newer version of webpack.

(ERROR in ./src/$$_lazy_route_resource lazy namespace object.)

For now i resolved my issue by migrating back to "@angular-devkit/build-angular": "0.9.0-rc.3".

@alan-agius4
Copy link
Collaborator

Relates to #6373

@alan-agius4
Copy link
Collaborator

Closing this in favour of #6373 (comment)

@aaronfrost
Copy link

If anyone needs help lazy loading modules and need something that isn't a route change, please check this out: https://www.npmjs.com/package/@herodevs/lazy-af

It's a component that makes it drop-dead simple to lazy load modules on demand. It's literally easier than the loadChildren property on a route.

@woppa684
Copy link
Author

@aaronfrost it only doesn't solve the issue I created this feature request for: be able to use the lazyModules option to lazily load a module from outside your project root (e.g. from node_modules) in AOT mode. It still needs the same workaround (create a proxy module). It also uses Angular internal API and therefore is just another workaround. Nice work, but no silver bullet :)

@unspike
Copy link

unspike commented Feb 13, 2019

@woppa684 have you found a possible solution for arrow function declaration with AOT loadChildren : () => ModuleName?

@woppa684
Copy link
Author

No, I don't use the router...

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants