Steve P
Steve P

Reputation: 19397

What prevents Require'ed scripts from injecting more script tags

I am trying to use some older scripts in an AMD/Require site. Some of these older scripts inject other scripts through the use of document.write or document.writeln of tags. Below is a simplified form of what's happening:

script1.js:

console.log('script1');
document.writeln("<script src='script2.js'></script>");

script2.js

console.log('script2');

If I load script1 in the classic way, DOM shows both script tags are present and console output shows that both are executed:

<head>
    <script src="script1.js"></script>
</head>
<body></body>

BUT If I load script1 via RequireJS, DOM shows only the script1 tag. Console output shows that script1 is executed, but the document.writeln is apparently ignored and thus script2 is not added to the DOM:

<head>
    <script src="require-jquery.js"></script>
    <script language="javascript">
        require( ['script1'], function( ) { } );
    </script>
</head>
<body></body>

What prevents this additional script from being inserted into the DOM? I'm suspect I would have other issues with load order even if the above did work correctly. But I want to understand this hole in my knowledge of what RequireJS is doing differently that prevents the additional script from loading.

I am using version 2.1.4 of RequireJS. The behavior is the same on Firefox and Chromium.

EDIT: I forgot to mention that in the real scenario, the path to 'script2' is dynamic based on some server-side logic as the first script is generated.

EDIT2: I obscured something else in my attempt to boil down the scenario: I can't (easily) change these old libraries as they are controlled by a different division of the company and are partially dynamic based on server-side logic (which again, I don't control). So as @ddotsenko suggested, maybe I should rephrase the question: how does one take some legacy scripts that depend on injecting script tags, and make them fit into the rest of the site that is trying to do the right thing by using AMD/RequireJS? The suggested shim approach comes close but doesn't work because the dependencies are unknown.

Upvotes: 1

Views: 174

Answers (1)

Latikov Dmitry
Latikov Dmitry

Reputation: 996

The problem is document.write() does not work after page load (and RequireJS uses XHR).

But you can use "shim" to predefine dependencies of your old modules - http://requirejs.org/docs/api.html#config-shim

config.js

require.config({

    deps: ["main"],

    shim: {
        script1: {
            deps: ['script2'],
            exports: "someScript1Object"
        }
    }
});

main.js

require(
    [ "script1" ],
    function(someScript1Object) {
        // ...
    }
);

And console output is

script2
script1 

UPDATE. Second variant: override document.write / document.writeln

You can use trick from ControlJS - overriding document.write. Try this code:

require.docwrite = function(text){
    var aMatches = text.match(/src='([^']*)/i) ||
        text.match(/src="([^"]*)/i) ||
        text.match(/src=([^ >]*)/i);
    if ( aMatches ) {
        var url = aMatches[1];
        require([ url ]);
    }
}

document.write = require.docwrite;
document.writeln = require.docwrite;

Upvotes: 1

Related Questions