The issue is caused by package @angular/compiler and/or @angular/core and/or @angular/router
Yes, the previous version in which this bug was not present was: 7.2.1
I try to load a project library (named shell) as a route "loadChildren", with 2 diff茅rents option :
This 2 ways work correctly on dev mode, but failed on AOT builded mode with an error message. And the route is not loaded.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { FlexLayoutModule } from '@angular/flex-layout';
import { ProfileComponent } from './profile/profile.component';
import { TranslateModule } from '../translate/translate.module';
import { GhostModule } from '../ghost/ghost.module';
import { DataModule } from '../data/data.module';
import { ProfileRoutingModule } from './profile-routing.module';
import { ProfileCardComponent } from './profile-card/profile-card.component';
@NgModule({
declarations: [
ProfileComponent,
ProfileCardComponent
],
imports: [
CommonModule,
MatCardModule,
MatListModule,
MatButtonModule,
MatIconModule,
TranslateModule,
FlexLayoutModule,
GhostModule,
DataModule,
ProfileRoutingModule
],
exports: [
ProfileCardComponent
]
})
export class ProfileModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SecureGuard } from 'shell';
import { HomeComponent } from './home/home.component';
export function loadProfile() {
return import('shell').then(m => m.ProfileModule);
}
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: loadProfile // Here the error at runtime, the error message appear when I go to /profile
}, {
path: '**',
component: HomeComponent
}]
}];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Uncaught Error: Uncaught (in promise): Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded
at e.Jr (main.41ff3398f5c3f189c836.js:1)
at t.project (main.41ff3398f5c3f189c836.js:1)
at t._tryNext (main.41ff3398f5c3f189c836.js:1)
at t._next (main.41ff3398f5c3f189c836.js:1)
at t.next (main.41ff3398f5c3f189c836.js:1)
at e._subscribe (main.41ff3398f5c3f189c836.js:1)
at e._trySubscribe (main.41ff3398f5c3f189c836.js:1)
at e.subscribe (main.41ff3398f5c3f189c836.js:1)
at e.call (main.41ff3398f5c3f189c836.js:1)
at e.subscribe (main.41ff3398f5c3f189c836.js:1)
at Z (polyfills.06b93379260cc1d8e708.js:1)
at Z (polyfills.06b93379260cc1d8e708.js:1)
at polyfills.06b93379260cc1d8e708.js:1
at e.invokeTask (polyfills.06b93379260cc1d8e708.js:1)
at Object.onInvokeTask (main.41ff3398f5c3f189c836.js:1)
at e.invokeTask (polyfills.06b93379260cc1d8e708.js:1)
at t.runTask (polyfills.06b93379260cc1d8e708.js:1)
at g (polyfills.06b93379260cc1d8e708.js:1)
at t.invokeTask [as invoke] (polyfills.06b93379260cc1d8e708.js:1)
at m (polyfills.06b93379260cc1d8e708.js:1)
Angular Version:
Angular CLI: 8.0.1
Node: 12.4.0
OS: darwin x64
Angular: 8.0.0
... animations, cdk, common, compiler, compiler-cli, core, forms
... language-service, material, material-moment-adapter
... platform-browser, platform-browser-dynamic, router
... service-worker
Package Version
------------------------------------------------------------
@angular-devkit/architect 0.800.1
@angular-devkit/build-angular 0.800.1
@angular-devkit/build-ng-packagr 0.800.1
@angular-devkit/build-optimizer 0.800.1
@angular-devkit/build-webpack 0.800.1
@angular-devkit/core 8.0.1
@angular-devkit/schematics 8.0.1
@angular/cli 8.0.1
@angular/flex-layout 8.0.0-beta.26
@angular/pwa 0.800.1
@ngtools/json-schema 1.1.0
@ngtools/webpack 8.0.1
@schematics/angular 8.0.1
@schematics/update 0.800.1
ng-packagr 5.2.0
rxjs 6.5.2
typescript 3.4.5
webpack 4.30.0
Anything else relevant?
I try to use on different CLI projects a Profile module from a CLI library (all on the same CLI project). This is not possible since angular 8.0.0
It's a known limitation:
Declaration syntax: It's important to follow the route declaration syntax
loadChildren: () => import('...').then(m => m.ModuleName)to allowngcto discover the lazy-loaded module and the associated NgModule. You can find the complete list of allowed syntax constructs here. These restrictions will be relaxed with the release of Ivy since it'll no longer use NgFactories.
See https://angular.io/guide/deprecations#loadchildren-string-syntax for more information.
If you believe this is worthing implementing please consider open a feature request to Angular CLI.
@trotyl thank you for quick answer,
export function loadProfile() {
return import('shell').then(m => m.ProfileModule);
}
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: loadProfile
}, {
path: '**',
component: HomeComponent
}]
}];
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: import('shell').then(m => m.ProfileModule)
}, {
path: '**',
component: HomeComponent
}]
}];
It is an issue with the CLI ? I have to add a bug on the cli project ?
loadChildren: import('shell').then(m => m.ProfileModule)
This is not lazy loading at all, you need to wrap an arrow function.
Sure, it is a bad copy paste @trotyl
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: () => import('shell').then(m => m.ProfileModule)
}, {
path: '**',
component: HomeComponent
}]
}];
If I don't declare it as an exported fonction, the build failed, because there is no ng factory for the module
I create same issue on CLI project : https://github.com/angular/angular-cli/issues/14700
Is shell also a copy-paste issue? You cannot load an NgModule from node_modules, it must belong to your project.
@trotyl, shell is a library from the same project, here the tsconfig file, so it is not a node_module, but an angular library :
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "esNext",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
],
"paths": {
"shell": [
"dist/shell"
],
"shell/*": [
"dist/shell/*"
]
}
}
}
and the piece of angular.json about the shell library :
"shell": {
"root": "projects/shell",
"sourceRoot": "projects/shell/src",
"projectType": "library",
"prefix": "lib",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss",
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:modules": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
},
"@schematics/angular:class": {
"spec": false
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/shell/tsconfig.lib.json",
"project": "projects/shell/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/shell/src/test.ts",
"tsConfig": "projects/shell/tsconfig.spec.json",
"karmaConfig": "projects/shell/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/shell/tsconfig.lib.json",
"projects/shell/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
Sorry for not making it clear, whether it's from node_modules doesn't matter, from your configuration:
"shell": [
"dist/shell"
],
It's not the same project, but a separately built library. (Where the source code resides doesn't make any difference)
ok @trotyl and @alan-agius4 , I already try it yesterday @alan-agius4 :
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SecureGuard } from 'shell';
import { HomeComponent } from './home/home.component';
import { ProfileWrapperModule } from './shared/profile-wrapper/profile-wrapper.module';
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: () => ProfileWrapperModule // For this feature I don't care about lazy loading, I just reuse module for all my portal apps
}, {
path: '**',
component: HomeComponent
}]
}];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProfileModule } from 'shell';
@NgModule({
declarations: [],
imports: [
CommonModule,
ProfileModule
]
})
export class ProfileWrapperModule { }
And it produce the same error
@alan-agius4 , you can close other issue if you want
For this 2 ways, that works on dev mode, build AOT is ok, but it is broke on runtime when I try to load the module
HI, the loadChildren syntax is your example above is not correct.
It should be:
loadChildren: () => import('./shared/profile-wrapper/profile-wrapper.module').then(m => m.ProfileWrapperModule)
@alan-agius4 , I have the same error than the 2 others ways :
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProfileModule } from 'shell';
@NgModule({
declarations: [],
imports: [
CommonModule,
ProfileModule
]
})
export class ProfileWrapperModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SecureGuard } from 'shell';
import { HomeComponent } from './home/home.component';
export function loadProfile() {
return import('./shared/profile-wrapper.module').then(m => m.ProfileWrapperModule);
}
const routes: Routes = [{
path: '',
canActivate: [SecureGuard],
children: [{
path: '',
component: HomeComponent
}, {
path: 'profile',
loadChildren: loadProfile
}, {
path: '**',
component: HomeComponent
}]
}];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Always good on local env, but not on AOT env.
When a click on the menu to go to my lazy loaded route, the lazy script .js is loaded but it seems to be empty :
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{Lz8n:function(n,o,r){"use strict";r.r(o),r.d(o,"ProfileWrapperModule",function(){return u});var u=function(){return function(){}}()}}]);
And an error appear on the console :
Uncaught Error: Uncaught (in promise): Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded
at e.Jr (main.b3a8916c121eaf6af8dc.js:1)
at t.project (main.b3a8916c121eaf6af8dc.js:1)
at t._tryNext (main.b3a8916c121eaf6af8dc.js:1)
at t._next (main.b3a8916c121eaf6af8dc.js:1)
at t.next (main.b3a8916c121eaf6af8dc.js:1)
at main.b3a8916c121eaf6af8dc.js:1
at e.invoke (polyfills.06b93379260cc1d8e708.js:1)
at Object.onInvoke (main.b3a8916c121eaf6af8dc.js:1)
at e.invoke (polyfills.06b93379260cc1d8e708.js:1)
at t.run (polyfills.06b93379260cc1d8e708.js:1)
at Z (polyfills.06b93379260cc1d8e708.js:1)
at Z (polyfills.06b93379260cc1d8e708.js:1)
at polyfills.06b93379260cc1d8e708.js:1
at e.invokeTask (polyfills.06b93379260cc1d8e708.js:1)
at Object.onInvokeTask (main.b3a8916c121eaf6af8dc.js:1)
at e.invokeTask (polyfills.06b93379260cc1d8e708.js:1)
at t.runTask (polyfills.06b93379260cc1d8e708.js:1)
at g (polyfills.06b93379260cc1d8e708.js:1)
Can you try to see if it works if you remove the loadProfile and pass an arrow function directly to loadChildren as per my previous example?
Not possible to build in AOT mode if I pass it directly as an arrow function.
@robinComa, the following syntax is supported by the AOT compiled
loadChildren: () => import('./shared/profile-wrapper/profile-wrapper.module')
.then(m => m.ProfileWrapperModule)
Check the lazy loading docs here: https://angular.io/guide/lazy-loading-ngmodules
Yes that works ! (it was not working on AOT when it is not proxyfied).
To conclude, the solution to load a library module is :
loadChildren: () => import('./shared/profile-wrapper/profile-wrapper.module')
.then(m => m.ProfileWrapperModule)
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProfileModule } from 'shell'; // From Angular project library
@NgModule({
declarations: [],
imports: [
CommonModule,
ProfileModule
]
})
export class ProfileWrapperModule { }
Thanks for support !
@alan-agius4 Is support for other import variants planned? I didn't find any issue stating support for different kinds of imports for lazy children.
It seems lazy children are limited to the application type and do not support libraries, right?
We have our router module in one library, because the setup is always the same and we don't want to duplicate it for every application.
Hi @CSchulz, that is correct, lazy loading routes are not supported in libraries, and at the moment there are no concrete plans yet to support this feature.
There is a greater discussion around this here: https://github.com/angular/angular-cli/issues/6373#issuecomment-453006158
@alan-agius4 Thanks for your fast reply. I have seen that discussion.
To support libraries the libraries needs to provide the factories itself? I have tried to investigate what is missing for supporting it.
I know it's closed but, M I the only one that are is not able to let it work on AOT or PROD ?? proxyfied or not, inside the project or from node_modules AOT (or PROD) compilation always give me "Error: Runtime compiler is not loaded".
Thanks in advance
I am also getting same error when adding Dynamic Component. What is the resolution for this?
Anyone still having this problem, you might be having the same problem as me and I found the answer here:
In summary, I was using backticks rather than single quotes when giving the path to the module I wanted to load.
@BerBevans It works like a charm. Thanks for pointing this out.
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._
Most helpful comment
Yes that works ! (it was not working on AOT when it is not proxyfied).
To conclude, the solution to load a library module is :
Thanks for support !