Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 AOT and Lazy loading

Tags:

angular

I have an app that lazy loads its feature components. Everything is fine and dandy as long as I don't AOT compile (which after days of struggling I got working).

My initial page load is super quick now. However, when I click any of my nav links which are supposed to lazy load that feature, I get a 404 and rightly so. There is a request being made to myfeature.module.ngfactory.js but this file does not exist. I have followed the cookbook on the dev site but it does not go into details on how to get lazy loads working. I see that my AOT compile creates a myfeature.module.ngfactory.ts but does not create a myfeature.module.ngfactory.js file. How do I go about creating this file? My tsconfig-aot.json file looks like this:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "es2015",
      "dom"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "noImplicitAny": false,
    "sourceMap": true,
    "suppressImplicitAnyIndexErrors": true,
    "target": "es5"
  },
  "files": [
    "app/shared/shared.module.ts",
    "app/app.module.ts",
    "app/myfeature/myfeature.module.ts",
    "main.ts"
  ],
  "angularCompilerOptions": {
    "skipMetadataEmit": true
  },
  "exclude": [
    "node_modules/*",
    "**/*-aot.ts"
  ]
}

I feel like I am missing something. Looks like the bootstrap process is the one that creates app.module.ngfactory.js but there is nothing triggering the creation of myfeature.module.ngfactory.js.

like image 515
mithun_daa Avatar asked Nov 30 '16 14:11

mithun_daa


1 Answers

Routing behavior

With configuration:

const rootRoutingConfig = RouterModule.forRoot([{
  path: 'home',
  loadChildren: './home.module#HomeModule'
}]);

By default, when the user navigates to /home, application using JiT will have the following behavior:

With SystemJS download APP_BASE_HREF/home.module.js and after that use the HomeModule export.

In contrast, when you're using AoT, the default behavior of the router will be:

With SystemJS download APP_BASE_HREF/home.module.ngfactory.js and use the HomeModule export.

What is *.ngfactory

home.module.ngfactory.js is an artifact which is produced by the Angular's compiler. During compilation the compiler will produce *.ngfactory.(js|ts) files for all your components and modules. For further information about the compiler take a look at this link.

How to solve your problem?

What you need to do is to either:

  1. Configure the module loader that the router uses to load the bundles from the location where you've saved them.
  2. Provide a custom callback for loading the module bundles.
  3. Produce the application bundles and store them in the location which is going to be used by the module loader by default.

With the second approach I prototyped an example for angular-seed. Take a look at the lazy branch. You can build the application for production using AoT and lazy-loading by running: npm run build.prod.exp. Note that the example is not complete. It only applies basic bundling without any sophisticated strategy which takes care of proper dependency resolution.

like image 133
Minko Gechev Avatar answered Oct 26 '22 09:10

Minko Gechev