I've tried loading modules without router using SystemJsNgModuleLoader
, but couldn't get it to work:
this.loader.load(url).then(console.info);
I'm getting Cannot find module xxx
for whatever string I use for URL (aboslute/relative urls/paths... tried many options). I looked through Router source code and couldn't find anything other then this SystemJsNgModuleLoader
. I'm not even sure I should be using this...
This question was asked just yesterday at ng-europe 2016
conference - Miško & Matias answered:
Miško Hevery: One just has to get hold of the module, from there you can get the hold of component factory and you can dynamically load component factory anywhere you want in the application. This is exactly what the router does internally. So it's quite strait forward for you to do that as well.
Matias Niemelä The only special thing to note is that on the [Ng]Module there's something called
entryComponents
and that identifies components that could be lazy loaded - that's the entry into that component set. So when you have modules that are lazy loaded, please put the stuff intoentryComponents
.
...but it's not that strait forward without examples and poor docs on the subject (;
Anyone knows how to load modules manually, without using Route.loadChildren
? How to get hold of the module and what exactly is the stuff that should go into entryComponents
(I read FAQ, but can't try without actually loading module)?
To lazy load an image, display a lightweight placeholder image, and replace with the real full-size image on scroll. There are several technical approaches to lazy loading images: Inline <img> tags, using JavaScript to populate the tag if image is in viewport. Event handlers such as scroll or resize.
To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows. content_copy const routes: Routes = [ { path: 'items', loadChildren: () => import('./items/items. module'). then(m => m.
define where we want to load our component in the template with the ng-template tag, define its view query through ViewChild decorator, which gives us access to the DOM and defines the container to which the component will be added, finally, dynamic import the component and add it to the container.
To lazy load the component, we will use the import() method inside an async/await function. The above function first clears the container; otherwise, on every click of the button, the new instance of GreetComponent would be added in the container.
Anyone knows how to load modules manually, without using Route.loadChildren?
You can use SystemJsNgModuleLoader
to get module's factory:
this.loader.load('./src/lazy.module#TestModule').then((factory: NgModuleFactory<any>) => { console.log(factory); });
For Angular 8 see Lazy load module in angular 8
Here is how it can look like:
lazy.module.ts
@Component({ selector: 'test', template: `I'm lazy module`, }) export class Test {} @NgModule({ imports: [CommonModule], declarations: [Test], entryComponents: [Test] }) export class LazyModule { static entry = Test; }
app.ts
import { Component, NgModule, ViewContainerRef, SystemJsNgModuleLoader, NgModuleFactory, Injector} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' @Component({ selector: 'my-app', template: `<h2>Test lazy loading module</h2>`, }) export class AppComponent { constructor( private loader: SystemJsNgModuleLoader, private inj: Injector, private vcRef: ViewContainerRef) {} ngOnInit() { this.loader.load('./src/lazy.module#LazyModule') .then((moduleFactory: NgModuleFactory<any>) => { const moduleRef = moduleFactory.create(this.inj); const entryComponent = (<any>moduleFactory.moduleType).entry; const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent); this.vcRef.createComponent(compFactory); }); } } @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent ], providers: [SystemJsNgModuleLoader], bootstrap: [ AppComponent ] }) export class AppModule {}
this.loader.load('./src/test.module#TestModule').then((factory: NgModuleFactory<any>) => { console.log(factory); });
Plunker Example
There are two options to precompile module for AOT:
Use angular/cli build-in feature:
{ "projects": { "app": { "architect": { "build": { "options": { "lazyModules": [ <====== add here all your lazy modules "src/path-to.module" ] } } } } } }
See
app.module.ts
providers: [ SystemJsNgModuleLoader, provideRoutes([ { loadChildren: 'app/lazy/lazy.module#LazyModule' } ]) ],
app.component.ts
export class AppComponent implements OnInit { title = 'Angular cli Example SystemJsNgModuleLoader.load'; @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef; constructor(private loader: SystemJsNgModuleLoader, private inj: Injector) {} ngOnInit() { this.loader.load('app/lazy/lazy.module#LazyModule').then((moduleFactory: NgModuleFactory<any>) => { const entryComponent = (<any>moduleFactory.moduleType).entry; const moduleRef = moduleFactory.create(this.inj); const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent); this.container.createComponent(compFactory); }); } }
Github repo angular-cli-lazy
Lazy loading with webpack and AOT
Compilation using ngc
Initialization Compiler by using the following factory
export function createJitCompiler () { return new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler(); }
Github repo
[Angular 6]
Hello,
I share my solution here because I didn't find how to lazyload without router on stackoverflow .
The Yurzui's way works but he uses the Router module to compile the lazy module while I didn't want to use it.
In our src/angular.json
file we can ask to the @angular/cli to compile a module apart.
For that we add the lazyModules
key in "project" > "your-app-name" > "architect" > "build" > "options".
Like this :
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "lazy-load-app": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/lazy-custom-element-app", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "src/styles.css" ], "scripts": [], "lazyModules": [ "src/app/lazy-load/lazy-load.module", "src/app/another-lazy-load/another-lazy-load.module" ]
then we can call and load our compiled module.
Like this :
export class LoaderComponent implements OnInit { // tag where we gonna inject the lazyload module and his default compononent "entry" @ViewChild('container', { read: ViewContainerRef }) viewRef: ViewContainerRef; constructor( private loader: NgModuleFactoryLoader, private injector: Injector, private moduleRef: NgModuleRef<any>,) { } ngOnInit(): void { this.loader.load(this.pathModuleTemplate).then((moduleFactory: NgModuleFactory<any>) => { // our module had a static property 'entry' that references the component that want to load by default with the module const entryComponent = (<any>moduleFactory.moduleType).entry; const moduleRef = moduleFactory.create(this.injector); const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent); this.viewRef.createComponent(compFactory); }); } }
source: https://github.com/angular/angular-cli/blob/9107f3cc4e66b25721311b5c9272ec00c2dea46f/packages/angular_devkit/build_angular/src/server/schema.json
Hoping it can help someone :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With