Dynamically Loading <compose /> ViewModels using Webpack


#1

We have a number of enterprise applications using aurelia. Most of them are using jspm/systemjs or CLI. On one of our most recent greenfield apps I decided to use Webpack. It has proved more valuable on a number of levels of which I will not go into in this post. With webpack there is a new class you have to use in order to allow DI for your ViewModels called PLATFORM.

Route Example:

import { PLATFORM } from 'aurelia-framework';

...

{
    route: ['mypage'],
    name: 'my-page',
    moduleId: PLATFORM.moduleName('views/mypage/index', 'mypage'),
    nav: true,
    title: 'My Page'
}

When using <compose /> with dynamically loaded/bound ViewModels, it was not working. You cannot dynamically change your string inside the method PLATFORM.moduleName('views/mypage/index'). What I ended up as a work-around for this was to “register” my view models that would/could be used in the binding of the <compose />. So for example…

View

<template>
    <compose view-model.bind="theVM"></compose>
</template>

ViewModel

import { PLATFORM } from 'aurelia-framework'; // I originally had this in a separate service but wasn't necessary and caused confusion
PLATFORM.moduleName('./view-model-a');
PLATFORM.moduleName('./view-model-b');

export class Index {
    theVM;

    constructor(){
        // constructor stuff
    }

    setupComposeViewModel(){
        // logic to determin theVM name
        this.theVM = './view-model-a';
    }
}

#2

Have a look at GlobDependenciesPlugin in Wiki. It can globally add modules so that those artificial moduleName are not needed.

Usage example
new GlobDependenciesPlugin({ “configure”: [“ClientApp/customElements/filter//*.html", "ClientApp/views//*.{ts,scss,html}”] })

configure is the module with the configure function.


#3

Yes we’re using that too however one of the things we’re trying to accommodate is only loading what we need, when we need it which we’re doing using code splitting. If we load it globally, it will be loaded on the client whether they use it or not. This is not an issue on smaller apps but larger apps, specially with areas where users may never get to, we wanted to lower the files they need to load. But thanks for that tid bit.


#4

But your modules are not dynamically loaded anyway. Webpack includes everything marked with PLATFORM.moduleName into the bundle regardless whether users use it or not.

Even with code splitting into multiple bundles, I believe it’s more practical to use the plugin than including hacky calls across the files.


#6

When I use the aurelia method for code splitting PLATFORM.moduleName('views/media/index', 'media') in the routes, it splits out the viewmodel as well as all it’s depenencies, including the composed views. I verified that all those files (both view and viewmodel) are in the split file and that its not loaded until I route to that view that depends on them. I agree with splitting out the PLATFORM.moduleName() methods into a different class not necessary and noted that but was just an example. Just updated the code to reflect the aforementioned for future reference.