The problem with combining UMD (Require.js) modules and non-UMD modules

Here’s an interesting problem i recently encountered.

I’ve got a site using Require.js. I’m loading an external library that doesn’t use Require. This library loads some external dependencies, one of them being Mustache.js. This library doesn’t use Require for loading dependencies, but a simple system of inserting <script> tags with a src tag.

Well, here’s the problem. Mustache uses the Universal Module Definition. Simplified it looks like this:


    if (typeof define === 'function') {
        define( Mustache );
    } else {
        window.Mustache = Mustache;
    }

See the problem? Because i’m using Require this module exports itself using the define() call. However the external library i’m using expects its to be in global scope so doing


    Mustache.render()

Won’t work.

Actually, for some weird reason (maybe something with lazy loading and evaluating JS?) this seems to work in Chrome, but on the iPad it fails.

So, who’s wrong here? Should the UMD definition be redefined to always export a global variable? Or is the external library just ‘doing it wrong’ and should they not use an external library like this?

Unfortunately there’s no clearcut answer to that. For now, i see three different ways to fix this.

Load the UMD module before Require in a script tag

So, do something like this:


    <script src="http://example.com/mustache.js"></script>
    <script src="http://example.com/require.js"></script>
    <script>
        // Mustache will be available before Require, and will attach itself
        // to the global scope.
        var html = Mustache.render();
    </script>

Load the UMD module with Require, but re-attach to the global scope

This is a bit hacky, but maybe a better solution than having a seperate script tag.


    // First load the UMD module dependency and attach to global scope again
    require(['/example/mustache'], function(Mustache) {
        window.Mustache = Mustache; // re-attach to global scope

        // Now load the problematic module
        require(['/example/module'], function() {
            // This module can use Mustache as a global variable
        });
    });

Change the UMD definition

I guess this is only interesting if the problematic dependency is also under your control, but you could change the UMD definition to something like this:


    window.Mustache = Mustache;

    if (typeof define === 'function') {
        define( Mustache );
    }

Add a comment