question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@ngtools/webpack :: Lazy Loaded Routes Not Built In Build With DLL Bundles

See original GitHub issue

Context

note: this is isolated to @ngtools/webpack

Steps to Reproduce

Please see the example application in the example repository. The README for that project includes a summary of the details outlined in this issue as well.

note: while this issue specifically describes a previously undescribed behavior with @ngtools/webpack and DLL bundles, I believe it’s a symptom of the same issue as the following issues:

#4431 #4346

Expected Behavior

Lazy loaded routes are built, regardless of whether Angular is bundled into a DLL

Actual Behavior

Lazy loaded routes are not built when Angular is bundled into a DLL

Details

I spent quite a bit of time digging through Webpack and the @ngtools plugin code to try to track this down (pretty new to both), and I’m fairly certain why this happens makes sense:

  1. The @ngtools/webpack plugin hooks into the ContextModuleFactory’s after-resolve plugin event to register the lazy loaded routes with the webpack compiler;
  2. The ContextModuleFactory is only created by the webpack parser implicitly parsing the @angular/src/linker/system_js_ng_module_factory_loader. This happens to have a context-requiring System.import statement which will cause the webpack parser to create an ImportContextDependency. The Webpack parser uses the ContextModuleFactory to convert the ImportContextDependency into a ContextModule, and in the process incidentally triggers the after-resolve plugin event;
  3. If the Webpack parser never parses the @angular library (as is the case when the @angular library is separately parsed for bundling in a DLL), lazy loaded routes are never registered, compiled, and chunked.

Workarounds

@ngtools/webpack version 1.2.4

Before the addition of the check in plugin.ts released in version 1.2.6 for @angular/core/src/linker, sticking a dummy “contextual” System.import call into any non-lazily-loaded code would trigger the relevant part of relevant part of plugin.ts:

declare var System: any;
function DummyObject() {
  this.f = {};
  System.import(this.f.a + this.f.b);
}

This is demonstrated in the example repository.

@ngtools/webpack version ^1.2.6

I haven’t been able to find an acceptable workaround following the addition of the @angular/core/src/linker check in 1.2.6. If you’re into really evil things (or are in a huge bind) you can always go into your local @ngtools/webpack plugin.js file and d some snipping, but that’s definitely not recommended.

Analysis and Proposed Solution

I’ll try my hand at a PR for this, but since I’m still wrapping my head around angular2, webpack, and the @ngtools/webpack plugin I thought I’d put my reasoning down here in case I’m missing something obvious:

Analysis

First, I’m not sure why @ngtools/webpack injecting lazy loaded route dependencies into Webpack depends on Webpack parsing @angulr/core/src/linker at all. As far as I can tell, @angular/core/src/linker doesn’t actually need to be parsed by the specific webpack compilation in order to build the lazy loaded routes. To be clear, I think the explicit check added in 1.2.6 at least makes it explicit that @angular/core/src/linker is expected to be parsed by the webpack compilation, I’m just not sure why that’s a necessary expectation.

Second, I’m not clear on why injecting the lazy loaded route dependencies is dependent on the Webpack compiler ContextModuleFactory plugin event, although that’s probably due to inadequate research on my part. I suspect it just has to do with having a module to which we can hitch the lazy loaded modules as dependencies, but I admit I don’t know for sure.

Finally, I don’t think the check for @angular/core/src/linker will ever match – as far as I can tell, result.resource points to the module that bootstraps the Angular2 application (the project’s main.ts, for example).

Just as reference, here are a couple other issues that I believe would be resolved by a simple refactor to how this is triggered:

#4431 #4346

Proposed Solution 1 :: Hook Into Webpack Plugin Event

This is probably the best of the two options, although it requires an appropriate Webpack plugin event to hook into. The idea is to entirely remove the need for a System.import call in some webpack-parsed dependency, and instead find a more appropriate plugin event to hook into. The key requirements would be:

  1. The plugin event needs to be a standard plugin event that will be executed every build;
  2. The plugin event needs to be executed at the appropriate time in the compilation (still not entirely sure when that is, but I suspect it’s just sometime during webpack parsing;
  3. The plugin event needs to be available across different supported versions of Webpack;
  4. The @ngtools/webpack plugin code needs to be defensive enough to avoid issues if there aren’t any lazy-loaded routes (I believe this is already true)

I’m really not confident this is possible, though.

Proposed Solution 2 :: Make @ngtools/webpack Inject Dummy ImportContextDependency

If the Webpack compiler’s ContextModuleFactory plugin event really is the best plugin event to hook into, theoretically we should be able to inject a dummy ImportContextDependency into the webpack compiler at the start of the compilation. This has a few benefits:

  1. absolute certainty that the webpack ContextModuleFactory plugin event will be triggered for every build
  2. no implicit dependency on @angular/core/src/linker having a System.import call
  3. increased code readability

Sorry if I’m totally off base or working on totally incorrect assumptions with any of this, and thanks in advance for your help!

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:9
  • Comments:12 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
thmclellancommented, Nov 10, 2018

Thanks so much @JLHwung for sharing webpack-dll-ng-module-loader - it helped me implement DLL features and reduce ng serve times from ~15 seconds to 1 second with NG6 and Ionic 4.

In case it helps anyone else new to webpack DLL’s with Angular, the ng serve webpack configuration options at https://github.com/meltedspark/angular-builders/tree/master/packages/dev-server seemed to work well enough with the DLL tutorial at https://medium.com/@emilycoco/how-to-use-the-dll-plugin-to-speed-up-your-webpack-build-dbf330d3b13c.

1reaction
JLHwungcommented, Jul 24, 2018

For those who would like to have a workaround on this issue, I just compose a tiny module webpack-dll-ng-module-loader to lazy load modules even when @angular/core is bundled in DLLs. No magic but copy pasting SystemJsNgModuleLoader and cheating AngularCompilerPlugin. The good news is that the we do not need any dummy “contextual” System.import call on non-lazily-loaded code. Just write loadChildren and it works out of box.

Special thanks to @tmeneau for such a detailed explanation on loadChildren mechanism. Without him I would probably spend much more time to dig out what happens.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Angular 5 lazy loading Error: Cannot find module
What worked for me, was 1) use absolute paths 2) Add the lazy loaded modules ... 'projectname' > architect > build > options...
Read more >
Lazy-loading feature modules - Angular
To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows. AppRoutingModule (excerpt)
Read more >
NgUpgrade with Lazy Loading - SyntaxSuccess
The first step is to create an application shell in Angular. The shell consists of three parts: app.module.ts, app.component.ts and app-routing.
Read more >
Lazy Loading | webpack
js , to be generated and technically "lazy-loads" it as soon as the script is run. The trouble is that no user interaction...
Read more >
angular/angular-cli - Gitter
route A module is not using rxjs filter but somehow its get loaded (the only thing ... well it might matter if you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found