简体   繁体   中英

Angular 4 Universal Lazy Loading Error

I have set up a new Angular CLI project to learn how to enable server-side rendering using Angular Universal.

I've set is up and everything is working great, but I decided to lazy-load a module called 'lazy'.

I did that, when using ng serve it works, but when Universal is running (with AOT), when I go to the lazy route and refresh the page I get this error, although I see the lazy component in the browser:

ERROR { Error: Uncaught (in promise): ReferenceError: System is not defined
ReferenceError: System is not defined
    at SystemJsNgModuleLoader.loadFactory (C:\Users\shachar\Desktop\universal\packages\core\src\linker\system_js_ng_module_factory_loader.ts:67:1)
    at SystemJsNgModuleLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\core\bundles\core.umd.js:5724:35)
    at RouterConfigLoader.loadModuleFactory (C:\Users\shachar\Desktop\universal\packages\router\src\router_config_loader.ts:71:1)
    at RouterConfigLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:3402:52)
    at MergeMapSubscriber.project (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:1570:74)
    at MergeMapSubscriber._tryNext (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:125:21)
    at MergeMapSubscriber._next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:115:12)
    at MergeMapSubscriber.Subscriber.next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Subscriber.ts:95:12)
    at ScalarObservable._subscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\observable\ScalarObservable.ts:51:18)
    at ScalarObservable.Observable._trySubscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Observable.ts:113:19)
    at resolvePromise (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:770:31)
    at resolvePromise (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:741:17)
    at C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:818:17
    at ZoneDelegate.invokeTask (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:424:31)
    at Object.onInvokeTask (C:\Users\shachar\Desktop\universal\packages\core\src\zone\ng_zone.ts:257:1)
    at ZoneDelegate.invokeTask (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:423:36)
    at Zone.runTask (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:191:47)
    at drainMicroTaskQueue (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:584:35)
    at Server.ZoneTask.invoke (C:\Users\shachar\Desktop\universal\node_modules\zone.js\dist\zone-node.js:490:25)
    at emitTwo (events.js:106:13)
  rejection:
   { ReferenceError: System is not defined
       at SystemJsNgModuleLoader.loadFactory (C:\Users\shachar\Desktop\universal\packages\core\src\linker\system_js_ng_module_factory_loader.ts:67:1)
       at SystemJsNgModuleLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\core\bundles\core.umd.js:5724:35)
       at RouterConfigLoader.loadModuleFactory (C:\Users\shachar\Desktop\universal\packages\router\src\router_config_loader.ts:71:1)
       at RouterConfigLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:3402:52)
       at MergeMapSubscriber.project (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:1570:74)
       at MergeMapSubscriber._tryNext (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:125:21)
       at MergeMapSubscriber._next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:115:12)
       at MergeMapSubscriber.Subscriber.next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Subscriber.ts:95:12)
       at ScalarObservable._subscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\observable\ScalarObservable.ts:51:18)
       at ScalarObservable.Observable._trySubscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Observable.ts:113:19)
     __zone_symbol__currentTask:
      ZoneTask {
        _zone: [Object],
        runCount: 0,
        _zoneDelegates: null,
        _state: 'notScheduled',
        type: 'microTask',
        source: 'Promise.then',
        data: undefined,
        scheduleFn: undefined,
        cancelFn: null,
        callback: [Function],
        invoke: [Function] } },
  promise:
   ZoneAwarePromise {
     __zone_symbol__state: 0,
     __zone_symbol__value:
      { ReferenceError: System is not defined
          at SystemJsNgModuleLoader.loadFactory (C:\Users\shachar\Desktop\universal\packages\core\src\linker\system_js_ng_module_factory_loader.ts:67:1)
          at SystemJsNgModuleLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\core\bundles\core.umd.js:5724:35)
          at RouterConfigLoader.loadModuleFactory (C:\Users\shachar\Desktop\universal\packages\router\src\router_config_loader.ts:71:1)
          at RouterConfigLoader.load (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:3402:52)
          at MergeMapSubscriber.project (C:\Users\shachar\Desktop\universal\node_modules\@angular\router\bundles\router.umd.js:1570:74)
          at MergeMapSubscriber._tryNext (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:125:21)
          at MergeMapSubscriber._next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\operator\mergeMap.ts:115:12)
          at MergeMapSubscriber.Subscriber.next (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Subscriber.ts:95:12)
          at ScalarObservable._subscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\observable\ScalarObservable.ts:51:18)
          at ScalarObservable.Observable._trySubscribe (C:\Users\shachar\Desktop\universal\node_modules\rxjs\src\Observable.ts:113:19) __zone_symbol__currentTask: [Object] } },
  zone:
   Zone {
     _properties: { isAngularZone: true },
     _parent:
      Zone {
        _properties: {},
        _parent: null,
        _name: '<root>',
        _zoneDelegate: [Object] },
     _name: 'angular',
     _zoneDelegate:
      ZoneDelegate {
        _taskCounts: [Object],
        zone: [Circular],
        _parentDelegate: [Object],
        _forkZS: null,
        _forkDlgt: null,
        _forkCurrZone: [Object],
        _interceptZS: null,
        _interceptDlgt: null,
        _interceptCurrZone: [Object],
        _invokeZS: [Object],
        _invokeDlgt: [Object],
        _invokeCurrZone: [Circular],
        _handleErrorZS: [Object],
        _handleErrorDlgt: [Object],
        _handleErrorCurrZone: [Circular],
        _scheduleTaskZS: [Object],
        _scheduleTaskDlgt: [Object],
        _scheduleTaskCurrZone: [Circular],
        _invokeTaskZS: [Object],
        _invokeTaskDlgt: [Object],
        _invokeTaskCurrZone: [Circular],
        _cancelTaskZS: [Object],
        _cancelTaskDlgt: [Object],
        _cancelTaskCurrZone: [Circular],
        _hasTaskZS: [Object],
        _hasTaskDlgt: [Object],
        _hasTaskDlgtOwner: [Circular],
        _hasTaskCurrZone: [Circular] } },
  task:
   ZoneTask {
     _zone:
      Zone {
        _properties: [Object],
        _parent: [Object],
        _name: 'angular',
        _zoneDelegate: [Object] },
     runCount: 0,
     _zoneDelegates: null,
     _state: 'notScheduled',
     type: 'microTask',
     source: 'Promise.then',
     data: undefined,
     scheduleFn: undefined,
     cancelFn: null,
     callback: [Function],
     invoke: [Function] } }

And no, I am not using SystemJS at all.

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { LazyModule } from './lazy/lazy.module';
import { HomeComponent } from './home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'universal' }),
    RouterModule.forRoot([
      {
        path: '',
        component: HomeComponent
      },
      {
        path: 'lazy',
        loadChildren: './lazy/lazy.module#LazyModule'
      }
    ])
  ],
  providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
  bootstrap: [AppComponent]
})
export class AppModule { }

lazy.module.ts:

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

import { LazyComponent } from './lazy.component';

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

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';

@NgModule({
  imports: [
    ServerModule,
    AppModule
  ],
  bootstrap: [AppComponent]
})
export class AppServerModule { }

server.ts: (express)

import 'reflect-metadata';
import 'zone.js/dist/zone-node';

import * as Express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';

const { AppServerModuleNgFactory } = require('../dist/ngfactory/src/app/app.server.module.ngfactory');

const app = Express();

enableProdMode();

const PORT = 4000;

const template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString();

app.engine('html', (_, options, callback) => {
  const opts = { document: template, url: options.req.url };

  renderModuleFactory(AppServerModuleNgFactory, opts)
    .then(html => callback(null, html));
});

app.set('views', join(__dirname, '..', 'dist'));
app.set('view engine', 'html');

app.get('*.*', Express.static(join(__dirname, '..', 'dist')));

app.get('*', (req, res) => {
  res.render('index', { req });
});

app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`);
});

I am glad the universal is working but it's bad to get this error message every refresh.

There is issue with Angular AOT CLI lazy load with server side rendering. Server is not aware of "System" which is default loader of angular. So in that case one need to add angular2-template-loader'and 'angular2-router-loader' for template loading on server side via webpack configuration.

Lazy loading using the CLI's bundler is not currently supported, see here . It's planned for an upcoming release and is under active development, so just hang tight in the meantime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM