4
votes

Consider this:

<script src='global.js'></script>
<script src='require.js'></script>
<script>
require(['modular_foo'], function() {
  //do stuff
});

...and in side global.js we have, among other things:

//global.js
$.getScript("modular_bar.js");

where both modular_foo and modular_bar are anonymously defined AMD modules. Using requireJS, loading something like the above would give you our favourite error, mismatched anonymous define() modules.

It's fine enough as to why that error occurs (read up on that page if you'd like to know), but the problem is, what if you can't get out of this situation?

I'm working in an established platform which is very gradually migrating to a RJS flow, for now there's no way out of using both inline legacy scripts (some of which have AMD checks to trigger define()) and our requireJS entry-point simultaneously.

In some cases I can simply place inline AMD-compatible scripts above loading the require.js library, but that doesn't work when you need to load other things (modular_bar.js) asynchronously depending on the DOM content. I could also just comment out all AMD checks from those files loading externally to RJS but that's preventing making them incompatible with ever being loaded in a modular flow.

Anyone out there had a similar experience? How do you blend your flows to overcome these sorts of conflicts?

1

1 Answers

0
votes

I do not have experience using this solution in a production environment but I spent a couple days on this question figuring out the best way to approach it.

You can use a modified RequireJS library that does not allow the anonymous define's to execute, if it is being passed through eval. Also, you can disallow any define calls by removing type check for string on name in the snippet below.

The following snippet is a modification to RequireJS that will ignore anonymous defines if being called by eval. You can find the fully modified require.js in this GitHub Gist.

The code relies on the parse-stack library. If you can't include the library before RequireJS, I suggest just concatenating it to the top of of the file.

Demo

// This is a snippet of RequireJS
// ...
define = function (name, deps, callback) {
    var node, context;

    // We will allow named modules to be defined by `eval`
    if (!(typeof name == 'string' || name instanceof String))
    {
        var stack = parseStack(new Error());

        // If we find any eval in the stack, do not define the module
        // This is to avoid the "Mismatched anonymous define() module" error
        // Caused by executing an anonymous define without requireJS
        for(var i = 0; i < stack.length; i++)
        {
            if(stack[i].name == "eval")
            {
                return;
            }
        }
    }

    // ...