Angular 2 routing submodules with AOT and Rollup

What's the correct way to set up a submodule in Angular 2 so that it works after AOT and rollup? I don't care about lazy loading and would be happy to have all submodules merged together, but loadChildren

is the cleanest way to reference a submodule and use it correctly <router-outlet>

, and although I've tried various methods, none will work either in development or production.

I followed the instructions in the AOT cookbook to prepare my application for deployment. My module structure is root> account> admin and I want admin routes to be loaded into the output defined by the account component.

Here's the router config for the account module:

import { NgModule } from '@angular/core';
import { AdminModule }   from './admin/admin.module';

const accountRoutes: Routes = [{
    path: 'account',
    component: AccountComponent,
    children: [
        { path: 'setup', component: SetupComponent },
        { path: 'admin', loadChildren: () => AdminModule }
    ]
}];

      

This works in development, but NGC compilation fails with Error: Error encountered resolving symbol values statically. Reference to a local (non-exported) symbol 'accountRoutes'.

I added export to accountRoutes

, but that also won't compile with Error: Error encountered resolving symbol values statically. Function calls are not supported.

.

One suggestion was to use a string instead of a function so that NGC can compile the code:

loadChildren: 'app/account/admin/admin.module#AdminModule'

      

This works in development and compilation, but the compiled application does not start because SystemJS is not available. Mistake:

ERROR Error: Uncaught (in promise): TypeError: System.import is not a function
TypeError: System.import is not a function
at t.loadFactory (build.js:6)
at t.load (build.js:6)
at t.loadModuleFactory (build.js:12)

      

I tried to include SystemJS in the build but couldn't find a separate module file app/account/admin/admin.module.ngfactory

- after collapsing everything in one build.js file. There might be a way to create separate drives for each submodule, but that's a lot of work.

I found a suggestion to reference the exported function:

export function loadAdminModule() {
    return AdminModule;
}

loadChildren: loadAdminModule

      

This works in development, but in production the runtime compiler is not available, so it registers build.js:1 ERROR Error: Uncaught (in promise): Error: Runtime compiler is not loaded

.

The helper function can be changed, so it works in production by referencing NgFactory instead, but that won't work in development.

import { AdminModuleNgFactory }   from '../../../aot/src/app/account/admin/admin.module.ngfactory';

export function loadAdminModule() {
    return AdminModuleNgFactory;
}

loadChildren: loadAdminModule

      

Is there a supported use case loadChildren

to make it work with the instructions in the AOT cookbook? Is it better to use webpack?

+3


source to share


2 answers


For those having the same problem, here's a temporary workaround. Hopefully a better answer will come soon.

Now I am defining my submodules in a dedicated file submodules.ts

. I have two versions of this file, one submodules-jit.ts

for development and one submodules-aot.ts

for AOT / rollup deployment for production. I gitignore submodules.ts

and added commands to my scripts npm start

and npm build:aot

that are substituted for what I want .

// submodules-jit.ts
import { AdminModule } from './account/admin/admin.module'
export function adminModule(): any { return AdminModule; }

// submodules-aot.ts
import { AdminModuleNgFactory } from '../../aot/src/app/account/admin/admin.module.ngfactory'
import { AdminModule } from './account/admin/admin.module'
export function adminModule(): any { return AdminModuleNgFactory; }
export function adminModuleKeep(): any { return AdminModule; }

      

The admin module must be listed in the AOT file for it to be saved.

Then I use the function adminModule

in my routes:



import { adminModule } from '../submodules'
{ path: 'admin', loadChildren: adminModule }

      

Finally, for convenience, the npm scripts end up in the correct file.

"build:aot": "cp src/submodules-aot.ts src/app/submodules.ts && ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
"start": "cp src/submodules-jit.ts src/app/submodules.ts && concurrently \"npm run build:watch\" \"npm run serve\""

      

Needless to say, this is a terrible hack, but it keeps the routing files clean and most of the evil in one place.

+2


source


In my case, I solved it with your tip on loading routes from an external module and then read this issue on the angular / cli page .

So I figured out the refactoring of my routes from:

import { TestModule } from './pathToModule/test.module';

export function exportTestModule() {
    return TestModule;
}

. . .

{
    path: 'test',
    loadChildren: exportTestModule
}

      



To:

. . .
{
    path: 'test',
    loadChildren: './pathToModule#TestModule'
}

      

0


source







All Articles