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
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.
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.
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.
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) 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'
}
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