note: this is isolated to @ngtools/webpack
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:
Lazy loaded routes are built, regardless of whether Angular is bundled into a DLL
Lazy loaded routes are not built when Angular is bundled into a DLL
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:
after-resolve plugin event to register the lazy loaded routes with the webpack compiler;@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;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._
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.
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:
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:
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:
I'm really not confident this is possible, though.
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:
ContextModuleFactory plugin event will be triggered for every buildSystem.import callSorry if I'm totally off base or working on totally incorrect assumptions with any of this, and thanks in advance for your help!
We actually spent a fair bit of time trying to get this to work, because we wanted to have a nice DLL setup. Ultimately we quit and found our rebuild performance increase elsewhere.
So you're pretty spot on how that mechanism works. The reason why the @angular/core/src/linker check needs to exist is that, even though you might declare a lazy route in user code (via router configuration), the linker in core is the file that ultimately does System.import.
The workaround you had did 'kinda' work iirc... I remember I did something similar. And although the lazy loaded chunks were generated I think they didn't actually work? I don't remember that bit well atm.
Anyway if you find a better approach we're happy to incorporate it really.
Thanks for the information, @filipesilva! I'm glad to know I'm at least heading in the right direction! I'll take a stab at this to see if I can find a different approach...
By the way, awesome work on the rebuild performance increase in the latest versions of @ngtools/webpack -- you guys are awesome! I kicked myself when I upgraded to the 1.2.8 version of the ngtools webpack plugin since there isn't really a need for trying to use DLLs anymore!
any news on this? got that too
Me too. Can't vendor split and get lazy loaded chunks with @ngtools. Works fine with Awesome-typescript-loader but of course you lose AOT.
It would be nice if this worked, however I found that I don't even need to put angular into a DLL bundle. In fact I was importing
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/common',
'@angular/forms',
'@angular/http',
'@angular/router',
into my vendors bundle, but when I removed them just, my app still compiled and ran even though I did not add them into the app bundle. So actually I don't see the point of putting them into the vendor bundle or the app bundle since webpack automatically resolves all the angular dependencies necessary from them component and module named import statements.
But this does slow down the webpack build, which is not cool
I might just end up dropping this @ngtools/webpack plugin and using ngc on command line to generate AOT files combined with awesome-typescript-loader since no solution appears to be in the works.
Any progress on the issue? Even a workaround would be welcome...
I would like to use lazy loading in my project but I have notice that initial build speed in significantly slower without DllPlugin.
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.
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.
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 meltedspark/angular-builders:packages/dev-server@
masterseemed to work well enough with the DLL tutorial at medium.com/@emilycoco/how-to-use-the-dll-plugin-to-speed-up-your-webpack-build-dbf330d3b13c.
I have tried this solution in ng7, but failed
I think this should be fixed by using the import() syntax for lazy routes instead of the old string syntax. You can find more information about this move in https://angular.io/guide/deprecations#loadchildren-string-syntax.
The reason it didn't work before is that lazy routes were actually imported via a special System.import located in @angular/core. But using the dynamic import() syntax that isn't a problem anymore.
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._