Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AOT compiler - include lazy loaded external module

I am trying to include external module (hosted in git/npm repository) as lazy-loaded module in my Angular application.

I am compiling my external module with ngc compiler:

node_modules/.bin/ngc -p tsconfig-aot.json

This is how my compiler config looks:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "baseUrl": "src",
    "declaration": true,
    "outDir": "./release/src"
  },
  "files": [
    "./src/index.ts"
  ],
  "angularCompilerOptions": {
    "genDir": "release",
    "skipTemplateCodegen": true,
    "entryModule": "index#ExternalModule",
    "skipMetadataEmit": false,
    "strictMetadataEmit": true
  }
}

And in my main app I am lazy loading given module:

RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full'},
      { path: 'lazy', loadChildren: './lazy/lazy.module#LazyModule'},
      { path: 'external', loadChildren: '@angular-universal-serverless/external-module/release#ExternalModule'}
])

For compilation purposes I am using @ngtools/webpack plugin.

The JIT compilation works without any problems, but AOT compilation gives me error:

ERROR in ./src/ngfactory lazy
Module not found: Error: Can't resolve '/path/to/my/project/angular-universal-serverless/src/ngfactory/node_modules/@angular-universal-serverless/external-module/release/src/index.js' in '/Users/mtreder/Documents/private/work/angular-universal-serverless/src/ngfactory'
 @ ./src/ngfactory lazy
 @ ./~/@angular/core/@angular/core.es5.js
 @ ./src/main.server.aot.ts

So I decided to check what is the output from ngc compiler (whic is called under the hood by the webpack plugin):

node_modules/.bin/ngc -p tsconfig.server.aot.json

And in fact, my module is missing in the /path/to/my/project/angular-universal-serverless/src/ngfactory/node_modules catalog.

ls src/ngfactory/node_modules/
@angular        @nguniversal        @types          idb         ng-http-sw-proxy    rxjs            typescript-collections

How can I force ngc to place given modules in the ngfactory output directory?

My main application can be found here: https://github.com/maciejtreder/angular-universal-serverless/tree/externalModule

And external module here: https://github.com/maciejtreder/angular-external-module

like image 293
Maciej Treder Avatar asked Oct 16 '17 16:10

Maciej Treder


People also ask

What are the features of using AOT compiler?

The Angular ahead-of-time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase before the browser downloads and runs that code. Compiling your application during the build process provides a faster rendering in the browser.

What is lazy loading module in Angular?

Lazy loading is an approach to limit the modules that are loaded to the ones that the user currently needs. This can improve your application's performance and reduce the initial bundle size. By default, Angular uses eager loading to load modules.

How lazy loading works internally in Angular?

Lazy loading is a useful technique for faster initial page loads. With lazy loading, your application loads faster by shipping only the essential startup code to the browser. Another code is placed inside of feature modules, which are loaded on demand. Lazy loading is a useful technique for faster initial page loads.

What does AOT mean ahead-of-time compilation Angular object templates both non of above?

The Ahead-of-time (AOT) compiler converts the Angular HTML and TypeScript code into JavaScript code during the build phase, i.e., before the browser downloads and runs the code.


1 Answers

1) The first problem here is that AOT compiler doesn't compile your module(node_modules folder is excluded by default), so you have to include it in files option of your ts configs:

tsconfig.browser.json

tsconfig.server.json

tsconfig.server.aot.json

"files": [
  "./node_modules/@angular-universal-serverless/external-module/release/src/externalComponent/external.module.d.ts"
],
"include": [
  "./src/main.browser.ts",
  "./src/app/lazy/lazy.module.ts",
  "./src/app/httpProxy/http-proxy.module.ts"
]

We can't add it to includes array because typescript will exclude it

Files included using "include" can be filtered using the "exclude" property

See more details in the doc

2) Then \node_modules\@angular-universal-serverless\external-module\release\package.json should has typings field like:

"name": "@angular-universal-serverless/external-module",
"main": "./src/index.js",
"typings": "./src/externalComponent/external.module.d.ts", <=== this one

We have to use external.module.d.ts because angular doesn't create ngfactory file for index.d.ts while @ngtools/webpack plugin creates map for ContextElementDependency:

const factoryPath = lazyRoute.replace(/(\.d)?\.ts$/, '.ngfactory.ts');
// where lazyRoute === .../external-module/release/src/externalComponent/external.module.d.ts
const lr = path.relative(this.basePath, factoryPath);
this._lazyRoutes[k + '.ngfactory'] = path.join(this.genDir, lr);

If you don't want to change package.json then change loadChildren field:

{ 
  path: 'external', 
  loadChildren: '@angular-universal-serverless/external-module/release/src/externalComponent/external.module#ExternalModule'
}

enter image description here

like image 180
yurzui Avatar answered Sep 19 '22 09:09

yurzui