setRoot fails when not hard coded

I am having trouble locating a module in my app startup. In my HTML markup for the page being loaded I have:

<div aurelia-app="main" data-feature="player/shell">
</div>

And I am pulling the feature name out in my main.js with:

let featureName = jQuery(aurelia.host).data('feature');
let featureModule = PLATFORM.moduleName(featureName);
aurelia.start().then(() => aurelia.setRoot(featureModule));

and this fails with:

Unable to find module with ID: player/shell

But, if I use a hard coded string instead:

aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName("player/shell")));

It works! Any idea why the hard coded version works but the version where the string is pulled from the HTML fails?

Edit: Forgot to mention this is an app created with the aurelia-cli using webpack

The module you want to use as root isn’t bundled. To make it work, you need to signal webpack (i guess?) to bundle it. If you really want to have dynamic root module, include everything in your src folder into the bundle, via new AureliaPlugin({ includeAll: 'mySourceFolder' })

Looking at my dist/app.bundle.js it appears that you are correct. The player/shell module isn’t bundled in there. Changing

new AureliaPlugin()

to

new AureliaPlugin({ includeAll: srcDir })

in my webpack.config.js doesn’t seem to help. Is there a list of steps you need to take for webpack each time you wan to add a new module to your app? I am used to just being able to add an html/js pair and re-build.

Including everything in your source folder should be the only step needed. Something else went wrong for your bundle. What does the error say ?

I found the solution from this comment. Basically if you don’t reference module statically you can’t load it at runtime because webpack won’t include it in the bundle. So I had to edit my root index.ts to load the module as a global resource:

import {FrameworkConfiguration} from 'aurelia-framework';
import {PLATFORM} from 'aurelia-pal';

export function configure(config: FrameworkConfiguration) {
  config.globalResources([
    PLATFORM.moduleName('player/shell')
  ]);
}

Thats a solid choice. I was pointing at the other way to help you get it to work in development easier only. Glad you got it to work

1 Like

If you are code splitting, for larger apps where you wouldn’t want to the end user loading the whole app, you can also just add it to the viewmodel where you’d want to use it. Then in your routes, just add your additional param to moduleName like PLATFORM.moduleName('views/myRoutedView', 'my-bundle-name').

so in your viewmodel that’s needing that module…

import { PLATFORM } from 'aurelia-framework';

PLATFORM.moduleName('player/shell'); // this tells webpack to include this in the bundle for this view

export class MyViewModel() {
  // do stuff
}

Of course if you want this to be available globally, then what you are using now works well.

2 Likes