Angular-cli: App-shell + ssr + lazy loading throw error Cannot find module

Created on 10 Nov 2018  路  14Comments  路  Source: angular/angular-cli

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Command (mark with an x)

- [ ] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Versions

Angular CLI: 7.0.5
Node: 10.9.0
OS: linux x64
Angular: 7.0.3
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router

@angular-devkit/architect         0.10.5
@angular-devkit/build-angular     0.10.5
@angular-devkit/build-optimizer   0.10.5
@angular-devkit/build-webpack     0.10.5
@angular-devkit/core              7.0.5
@angular-devkit/schematics        7.0.5
@angular/cli                      7.0.5
@ngtools/webpack                  7.0.5
@schematics/angular               7.0.5
@schematics/update                0.10.5
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.19.1

Repro steps

ng new universal-shell
cd universal-shell/
ng add @nguniversal/express-engine --clientProject universal-shell
ng generate app-shell shell --universal-project universal-shell --route shell --client-project universal-shell

create a module with route and configure it for lazy loading. Compile and try request the page point to this module. The server will throw a error. Here is a repo:
https://github.com/csbenjamin/app-shell-plus-univeral-plus-lazy-routing

The log given by the failure

Node Express server listening on http://localhost:4000
ERROR { Error: Uncaught (in promise): Error: Cannot find module './lazy/lazy.module.ngfactory'
Error: Cannot find module './lazy/lazy.module.ngfactory'
    at /home/cristiano/projects/test/universal-shell/dist/server.js:36928:11
    at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:546:26)
    at Object.onInvoke (/home/cristiano/projects/test/universal-shell/dist/server.js:18104:33)
    at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:545:32)
    at Zone.run (/home/cristiano/projects/test/universal-shell/dist/server.js:296:43)
    at /home/cristiano/projects/test/universal-shell/dist/server.js:1030:34
    at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:579:31)
    at Object.onInvokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:18095:33)
    at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:578:36)
    at Zone.runTask (/home/cristiano/projects/test/universal-shell/dist/server.js:346:47)
    at resolvePromise (/home/cristiano/projects/test/universal-shell/dist/server.js:972:31)
    at resolvePromise (/home/cristiano/projects/test/universal-shell/dist/server.js:929:17)
    at /home/cristiano/projects/test/universal-shell/dist/server.js:1031:17
    at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:579:31)
    at Object.onInvokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:18095:33)
    at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:578:36)
    at Zone.runTask (/home/cristiano/projects/test/universal-shell/dist/server.js:346:47)
    at drainMicroTaskQueue (/home/cristiano/projects/test/universal-shell/dist/server.js:753:35)
    at ZoneTask.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:658:21)
    at Server.ZoneTask.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:643:48)
  rejection:
   { Error: Cannot find module './lazy/lazy.module.ngfactory'
       at /home/cristiano/projects/test/universal-shell/dist/server.js:36928:11
       at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:546:26)
       at Object.onInvoke (/home/cristiano/projects/test/universal-shell/dist/server.js:18104:33)
       at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:545:32)
       at Zone.run (/home/cristiano/projects/test/universal-shell/dist/server.js:296:43)
       at /home/cristiano/projects/test/universal-shell/dist/server.js:1030:34
       at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:579:31)
       at Object.onInvokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:18095:33)
       at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:578:36)
       at Zone.runTask (/home/cristiano/projects/test/universal-shell/dist/server.js:346:47) code: 'MODULE_NOT_FOUND' },
  promise:
   ZoneAwarePromise {
     __zone_symbol__state: 0,
     __zone_symbol__value:
      { Error: Cannot find module './lazy/lazy.module.ngfactory'
          at /home/cristiano/projects/test/universal-shell/dist/server.js:36928:11
          at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:546:26)
          at Object.onInvoke (/home/cristiano/projects/test/universal-shell/dist/server.js:18104:33)
          at ZoneDelegate.invoke (/home/cristiano/projects/test/universal-shell/dist/server.js:545:32)
          at Zone.run (/home/cristiano/projects/test/universal-shell/dist/server.js:296:43)
          at /home/cristiano/projects/test/universal-shell/dist/server.js:1030:34
          at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:579:31)
          at Object.onInvokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:18095:33)
          at ZoneDelegate.invokeTask (/home/cristiano/projects/test/universal-shell/dist/server.js:578:36)
          at Zone.runTask (/home/cristiano/projects/test/universal-shell/dist/server.js:346:47) code: 'MODULE_NOT_FOUND' } },
  zone:
   Zone {
     _properties: { isAngularZone: true },
     _parent:
      Zone {
        _properties: {},
        _parent: null,
        _name: '<root>',
        _zoneDelegate: [ZoneDelegate] },
     _name: 'angular',
     _zoneDelegate:
      ZoneDelegate {
        _taskCounts: [Object],
        zone: [Circular],
        _parentDelegate: [ZoneDelegate],
        _forkZS: null,
        _forkDlgt: null,
        _forkCurrZone: [Zone],
        _interceptZS: null,
        _interceptDlgt: null,
        _interceptCurrZone: [Zone],
        _invokeZS: [Object],
        _invokeDlgt: [ZoneDelegate],
        _invokeCurrZone: [Circular],
        _handleErrorZS: [Object],
        _handleErrorDlgt: [ZoneDelegate],
        _handleErrorCurrZone: [Circular],
        _scheduleTaskZS: [Object],
        _scheduleTaskDlgt: [ZoneDelegate],
        _scheduleTaskCurrZone: [Circular],
        _invokeTaskZS: [Object],
        _invokeTaskDlgt: [ZoneDelegate],
        _invokeTaskCurrZone: [Circular],
        _cancelTaskZS: [Object],
        _cancelTaskDlgt: [ZoneDelegate],
        _cancelTaskCurrZone: [Circular],
        _hasTaskZS: [Object],
        _hasTaskDlgt: [ZoneDelegate],
        _hasTaskDlgtOwner: [Circular],
        _hasTaskCurrZone: [Circular] } },
  task:
   ZoneTask {
     _zone:
      Zone {
        _properties: [Object],
        _parent: [Zone],
        _name: 'angular',
        _zoneDelegate: [ZoneDelegate] },
     runCount: 0,
     _zoneDelegates: null,
     _state: 'notScheduled',
     type: 'microTask',
     source: 'Promise.then',
     data:
      ZoneAwarePromise { __zone_symbol__state: 0, __zone_symbol__value: [Error] },
     scheduleFn: undefined,
     cancelFn: null,
     callback: [Function],
     invoke: [Function] } }

Desired functionality

Mention any other details that might be useful


It seams related to https://github.com/angular/angular-cli/issues/9202

devkibuild-angular high broken bufix

All 14 comments

@csbenjamin thank you for the reproduction, this will be super helpful to get down debugging the issue straight away.

The problem seems to be that NgModuleFactoryLoader is not using ModuleMapNgFactoryLoader that is being defined in https://github.com/csbenjamin/app-shell-plus-univeral-plus-lazy-routing/blob/b7f95b689336cbb47cd476cd688a7ecf497da632/server.ts#L31-L38, but rather still using the SystemJsNgModuleLoader instead.

@vikerman, any idea why the application still uses the default providers instead of the once configured with ngExpressEngine in the server files?, Is this by design or a bug?

Also previously, with Angular 6 there was another workaround which was to configure the NgModuleFactoryLoader provider in the AppServerModule.

providers: [{
  provide: NgModuleFactoryLoader,
  useClass: ModuleMapNgFactoryLoader
}],

However this cannot be done in Angular 7 as MODULE_MAP is not an optional provider, and will cause a build error. StaticInjectorError(AppServerModule)[NgModuleFactoryLoader -> InjectionToken MODULE_MAP]:

After some more debugging I found a couple of more issues.

1) ModuleMapNgFactoryLoader requires MODULE_MAP (https://github.com/angular/universal/blob/master/modules/module-map-ngfactory-loader/src/module-map-ngfactory-loader.ts#L28) and it is not an Optional provider. However, this cannot be provided at application level.

  1. Using ModuleMapLoaderModule with the app-shell builder will cause a build error due to the above.

  2. Providers configured in server.ts are not overriding the NgModuleFactoryLoader that was configured to use SystemJsNgModuleLoader when calling the Router.forRoot In app.server.module.

Thanks for this issue, I have been struggling with this aswell. In Angular 6, Universal/SSR + App-Shell always worked perfectly for me straight away, but ever since Angular 7 I have never fully got it to work.

If I have wildcard routes in my router, e.g. path: '**' to catch wrong links and lazily-load a PageNotFound/404 module/component, it already fails when running

ng run my-app:app-shell

with

ERROR { Error: Uncaught (in promise): ReferenceError: System is not defined ReferenceError: System is not defined at SystemJsNgModuleLoader.loadFactory

If I remove the wildcard route and just leave my normal routes, it builds fine, but I run into the well known

ERROR { Error: Uncaught (in promise): Error: Cannot find module './views/home/home.module.ngfactory' Error: Cannot find module './views/home/home.module.ngfactory'

type of errors. The fix from https://github.com/angular/universal-starter/blob/master/server.ts (l. 30-39) never changed anything for me. There have been a couple of CLI updates since 7.0 with some changes sounding like they were related, but ultimately, it never worked since I upgraded from Angular 6 and I dropped the App-Shell for now.

@D2KX you are seeing this error System is not defined ReferenceError: System is not defined at SystemJsNgModuleLoader.loadFactory because the overriding of providers from server.ts is not effecting the application.

+1 Commenting as this affects us also.

Full repo steps:

git clone https://github.com/csbenjamin/app-shell-plus-univeral-plus-lazy-routing
cd app-shell-plus-univeral-plus-lazy-routing
npm i
npm run build:client-and-server-bundles && npm run compile:server
npm run serve:ssr

Seperate terminal

curl http://localhost:4000/lazy | grep 'lazy works'

Check logs both terminals, first terminal, you'll have an error, in the second grep will find no matches.

Hello - Sorry for the confusion. Dug to the bottom of it.

The thing needed to make Lazy routes work on the server is the ModuleMapLoaderModule - In the starter it is included here - https://github.com/angular/universal-starter/blob/master/src/app/app.server.module.ts#L14

Without this the SystemJSLoader is used and that blows up on the server.

Please add these lines manually for now in your app.server.module.ts.

import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';

...

@NgModule({
  imports: [
    AppModule,
     ...
    ModuleMapLoaderModule,
    ...
  ],
  bootstrap: [AppComponent],
})

I will fix ng g universal to add this line automatically.

@vikerman

I think most of us have set up ModuleMapLoaderModule, and this is kind of the problem, as the lazy module map is only getting provided in the server.ts for SSR, which is not accessible to the App-Shell during the build of the project, hence this issue.

@D2KX

The AppShell uses app.server.module.ts right? The ModuleMapLoaderModule needs to go in there.

Ah - That doesn't load the MODULE_MAP though. Will see how this was ever working before for AppShell. As a Node server this works now.

Looked into it more. The app shell scenario works as expected because it actually overrides the route configuration to just render a ShellComponent that has nothing to do with lazy loaded routes.

The above problem with SSR and lazy routes exists which I am trying to fix by moving the module-map-ngfactory-loader to @angular/platform-server and insert it in app.server.module.ts.

Till then manually add it as a work around.

This is being tracked by https://github.com/angular/universal/issues/1129 for ng add @nguniversal/express-engine to add ModuleMapLoaderModule to app.server.module.ts automatically. Till then add it manually as noted in https://github.com/angular/universal/blob/master/modules/module-map-ngfactory-loader/README.md

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rajjejosefsson picture rajjejosefsson  路  3Comments

sysmat picture sysmat  路  3Comments

hartjo picture hartjo  路  3Comments

delasteve picture delasteve  路  3Comments

purushottamjha picture purushottamjha  路  3Comments