0

I am considering using webpack in my existing knockout based SPA framework in order to lazy load models, as the user browses through the site

I had a look at the below thread Create individual SPA bundles with Webpack

and the accepted answer seemed very similar to what I am trying to achieve. Basically, each SPA page is comprised from a collection of components that are returned from the server in JSON format.

The client maps these components to individual js models. Right now, these js models are all bundled in 1 big file and served to the client, the 1st time the site is rendered.

I would like to break these components (via require and require.ensure) into chunks that will be loaded on demand with the help of webpack.

So, I fiddled around with the proposed solution from the above mentioned thread and it worked fine. I also added a root directive to webpack.config.js

    var webpack = require('webpack'),
    path = require('path');

var commonsPlugin =
    new webpack.optimize.CommonsChunkPlugin('common.js');

module.exports = {
    devtool1: 'eval-source-map',
    entry: {
        app: './app'
    },
    output: {
        path: __dirname + "/build",
        filename: '[name]-bundle.js',
        publicPath: "/code_split/build/"
    },
    watchOptions: {
        poll: 2000
    },
    resolve: {
        root: [
            path.resolve('./models/components')
        ],
        extensions: ['', '.js']
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel',
                query: {
                    presets: ['es2015']
                }
            }
        ]
    },
    plugins: [commonsPlugin]
}

so that I can require modules without specifying relative paths (each model is in a js module inside models/components directory)

Now the problem I run into is that I tried to extract all the requires from the switch statement to a function which returns a Promise, which will work nicely with my existing implementation

so instead of

var mod = window.location.hash.split('/')[1].toLowerCase();
switch(mod) {
    case "contacts":
        require(["./pages/contacts"], function(page) {
            // do something with "page"
        });
        break;
    case "tasks":
        require(["./pages/tasks"], function(page) {
            // do something with "page"
        });
        break;
}

I changed it to

    function loadModule(mo){
        return new Promise(function(resolve){
            require([mo], function(module){
                resolve(module.default);
            });
        });
    }

switch(mod) {
        case "contacts":
            promise = loadModule("contacts");
            break;
        case "tasks":
            promise = loadModule("tasks");
            break;
    }

After running webpack however, the above fails miserably. It seems to go into an infinite loop, as it ends up finding an alarmingly high number of modules to process and ends up spitting out numerous exceptions I am pretty sure this is caused from the loadModule function, since when I try with direct requires it works fine

Any ideas? Thanks

Community
  • 1
  • 1
Thomas
  • 4,641
  • 13
  • 44
  • 67

1 Answers1

1

Webpack uses static analysis to find out what modules to bundle (and how to bundle them). Because you are abstracting away the require, webpack can no longer figure out what exactly you are requiring. To avoid things breaking, it then tries to bundle everything you could possibly mean. In this case, that probably means literally every single JS file it can find in your project directory (including all JS files in node_modules).

If you want to promisify Webpack's async requires, you will have to just duplicate your code for each async bundle.

Ambroos
  • 3,456
  • 20
  • 27
  • Thanks for the help. So basically, I need the Promise in every case statement right? I am curious whether there is any other way to accomplish the same, since the way I see it, it is somewhat limiting and promotes duplication – Thomas Sep 23 '16 at 14:26
  • Right now there isn't. It doesn't promote duplication exactly, it just doesn't allow deduplication. Webpack really needs static analysis to work well, so there's simply no way around it. – Ambroos Sep 23 '16 at 14:58