Lazy loading on Mithril js



Hi,
on this tutorial, we'll be dealing with lazy-loading in Mithril.
On the Mithril documentation, this is described under Code splitting in the routes page as:

Code splitting

In a large application, it may be desirable to download the code for each route on demand, rather than upfront. Dividing the code-base this way is known as code splitting or lazy loading. In Mithril, this can be accomplished by returning a promise from the onmatch hook:
At its most basic form, one could do the following:

// Home.js
module.export = {
    view: function() {
        return [
            m(Menu),
            m("h1", "Home")
        ]
    }
}

// index.js
function load(file) {
    return m.request({
        method: "GET",
        url: file,
        extract: function(xhr) {
            return new Function("var module = {};" + xhr.responseText + ";return module.exports;")
        }
    })
}

m.route(document.body, "/", {
    "/": {
        onmatch: function() {
            return load("Home.js")
        },
    },
})
However, realistically, in order for that to work on a production scale, it would be necessary to bundle all of the dependencies for the Home.js module into the file that is ultimately served by the server.

Fortunately, there are a number of tools that facilitate the task of bundling modules for lazy loading. Here's an example using webpack's code splitting system:
// index.js
function load(file) {
    return m.request({
        method: "GET",
        url: file,
        extract: function(xhr) {
            return new Function("var module = {};" + xhr.responseText + ";return module.exports;")
        }
    })
}
m.route(document.body, "/", {
    "/": {
        onmatch: function() {
            return load("Home.js")
            // using Webpack async code splitting
            return new Promise(function(resolve) {
                require(['./Home.js'], resolve)
            })
        },
    },
})

This can also be achieved using es6 dynamic import and default export as follows:

// Home.js
const Home = {
    view: function() {
        return [
            m(Menu),
            m("h1", "Home")
        ]
    }
}
export default Home;

// index.js
m.route(document.body, "/", {
    "/": {
        onmatch: () => {
            // using Webpack async code splitting
            return new Promise((resolve) => {
                // using dynamic import
                import(/* webpackChunkName: "landing" */'./home.js').then((home) => {
                    resolve(home.default);
                }
            });
        },
    },
});


This is the same as above, using async await:

// Home.js
const Home = {
    view: function() {
        return [
            m(Menu),
            m("h1", "Home")
        ]
    }
}
export default Home;

// index.js
m.route(document.body, "/", {
    "/": {
        onmatch: () => {
            // using Webpack async code splitting
            return new Promise(async (resolve) => {
                // using dynamic import
                const home = await import(/* webpackChunkName: "home" */'./Home.js');
                resolve(home.default);
            });
        },
    },
});

Notice this /* webpackChunkName: "home" */
This name is used internally by webpack during module imports

Comments

Post a Comment

We Love Comments