Skip to content

Instantly share code, notes, and snippets.

@brandonroberts
Last active April 26, 2019 12:40
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save brandonroberts/02cc07face25886fe142c4dbd8da1340 to your computer and use it in GitHub Desktop.
Save brandonroberts/02cc07face25886fe142c4dbd8da1340 to your computer and use it in GitHub Desktop.
Webpack Async NgModule Loader
import {Injectable, NgModuleFactory, NgModuleFactoryLoader, Compiler, Type} from '@angular/core';
class LoaderCallback {
constructor(public callback) {}
}
export let load: Type = (callback: Function) => {
return new LoaderCallback(callback);
};
/**
* NgModuleFactoryLoader that uses Promise to load NgModule type and then compiles them.
* @experimental
*/
@Injectable()
export class AsyncNgModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler) {}
load(modulePath: string|LoaderCallback): Promise<NgModuleFactory<any>> {
if (modulePath instanceof LoaderCallback) {
let loader = (modulePath as LoaderCallback).callback();
return Promise
.resolve(loader)
.then((type: any) => checkNotEmpty(type, '', ''))
.then((type: any) => this.compiler.compileModuleAsync(type));
}
return Promise.resolve(null);
}
}
function checkNotEmpty(value: any, modulePath: string, exportName: string): any {
if (!value) {
throw new Error(`Cannot find '${exportName}' in '${modulePath}'`);
}
return value;
}
import {NgModuleFactoryLoader} from '@angular/core';
import {AsyncNgModuleLoader} from './async-ng-module-loader';

// Add to main providers
{provide: NgModuleFactoryLoader, useClass: AsyncNgModuleLoader}
import {load} from './async-ng-module-loader';

{
  path: 'lazy',
  loadChildren: load(() => new Promise(resolve => {
      (require as any).ensure([], require => {
        resolve(require('./lazy-module').LazyModule);
      })
    }))
},
@iurii-kyrylenko
Copy link

The following works for my startup in RC6:

    { path: 'task2', loadChildren: () =>
        new Promise(resolve =>
            (require as any).ensure([], () =>
                resolve(require('./task-2/task2.module').Task2Module)
            )
        )
    }

@AnotherStop, have you updated your typings.json?

@lghiur
Copy link

lghiur commented Sep 2, 2016

Hi @iurii-kyrylenko,

Can you please help me a bit as I'm out of solutions. I have tried your solution but I'm getting "No NgModule metadata found for '[object Promise]'" error. I want to mention that I don't use Typescript. I have placed bellow the code I'm using:

  • router
{
  path: 'style-guide',
  loadChildren: () =>
    new Promise(resolve => {
      return require.ensure([], () =>
        resolve(require('./style-guide.module').StyleGuideModule)
      );
    }

-style guide module

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';

import StyleGuideComponent from './style-guide.component';

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([
        { path: '', component: StyleGuideComponent }
    ])
  ],
  declarations: [
    StyleGuideComponent
  ]
})
export class StyleGuideModule {}

Thank you,
Laurentiu

@iurii-kyrylenko
Copy link

@lghiur,

I don't use Typescript

It's strange, because you're using @NgModule decorator function. This is typescript syntax.
Anyway, check tsconfig.json: a compiler option emitDecoratorMetadata should be set to the true.

@lghiur
Copy link

lghiur commented Sep 4, 2016

@iurii-kyrylenko I am transpiling my code with babel and I m using a decorator plugin. That s why I can use decorators without Typescript and I don t have a tsconfig file.

Thank you
Laurențiu

@qk44077907
Copy link

the same issue with @lialosiu

@brandonroberts
Copy link
Author

@qk44077907 @lialosiu are you still having this issue? With RC6 you don't need a custom loader anymore. I also have a webpack loader here you can use if you want to use string-based lazy loading: https://www.npmjs.com/package/angular2-router-loader

@satish-pokala
Copy link

satish-pokala commented Sep 13, 2016

hello can anyone help me,

Work this issue with RC5.

{
path: 'admin',
loadChildren: load(() => new Promise(resolve => {
return (require as any).ensure([], (require: any) => {
return resolve(require('./pages/dev/dev.module').default);
});
}))
},

because of require cannot find name.

@mineofcode
Copy link

mineofcode commented Nov 5, 2016

export let load: Type = (callback: Function) => {
return new LoaderCallback(callback);
};

Generic type 'Type' requires 1 type argument(s)

Getting above error while compile with ng serve

node -v 7.0.0
npm -v 3.10.8
angular-cli: 1.0.0-beta.19-3
editor : Visual Studio Code

please help me...

"dependencies": {
"@angular/common": "~2.1.0",
"@angular/compiler": "~2.1.0",
"@angular/core": "~2.1.0",
"@angular/forms": "~2.1.0",
"@angular/http": "~2.1.0",
"@angular/platform-browser": "~2.1.0",
"@angular/platform-browser-dynamic": "~2.1.0",
"@angular/router": "~3.1.0",
"bootstrap": "^3.3.7",
"core-js": "^2.4.1",
"jquery": "^3.1.1",
"rxjs": "5.0.0-beta.12",
"ts-helpers": "^1.1.1",
"zone.js": "^0.6.23"
},

Copy link

ghost commented Mar 22, 2017

Same error than @masagatech trying to fix it right now.

@haisaco
Copy link

haisaco commented Apr 11, 2017

same error @masagatech trying to fix it right now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment