Jamie Harding
Jamie Harding

Reputation: 383

Appending a JS file that contains document.write

I have a JS script that will .append() another script to the body and what it's appending looks like:

<script type=\"text\/javascript\" src=\"https:\/\/website\/creative\/camref:[ref]\/creativeref:[ref]\"><\/script>

inside this script it contains document.write() and I CANNOT modify this file.

It does not write what is inside the script to the website and how can I fix this? Would async work (I know about the async promise)?

Upvotes: 1

Views: 241

Answers (1)

Michael Geary
Michael Geary

Reputation: 28850

You have three options: serve, embrace, or replace.

Serve the script yourself

If you can put some code on your own server, you can have that code fetch the remote script and modify it on its way to your front-end code. Your JavaScript code will use a URL on your own site instead of the remote site. Your server code that handles this URL fetches the remote script and does a text replacement to change the document.write() call in the script with other code that works with your site, e.g. by using jQuery/DOM calls instead. Then it sends this modified script down as its own response.

This can work very well, but beware of potential issues with the terms of service of the remote script, and also possible rate limiting or worse, since all the requests to the remote server will now come from your server instead of your visitors' browsers.

Embrace document.write()

The script you're loading from the remote server assumes it will be loaded with a direct <script> tag in your page's <body>. That's the only time document.write() works as you might expect. If document.write() is called from a dynamic script after the page is loaded, it wipes out the current page content, as you discovered.

So instead of using .append() to load the remote script, load it the way it expects, with an actual <script> tag in the page itself. Then the script's document.write() will write into the page at the point where you load it, without wiping the rest of the page.

But what if you need to pass dynamic parameters to the script? Assuming you know or can calculate those parameters at the time the page is loaded, you can call document.write() in your own script (inline or in a .js file) to write the script tag that loads the remote script. This works just like having the remote <script> tag inline in your HTML, except you can create the URL on the fly.

If you need to pass parameters to the script that aren't known until later (e.g. from user input into the page), or if you can't load the script until later, this won't work.

Example:

<!-- This goes inside the <body> tag where you want the remote script. -->
<script>
    var value = 'test';
    document.write(
        '<script src="https://example.com/script?foobar=', value,
        '"><\/script>'
    );
</script>
<!-- The remote script's document.write() output will go here. -->

Replace document.write()

Provide your own implementation of document.write() that uses jQuery/DOM to take the text that would have been written and insert it dynamically where you want it.

Example:

// Do this in your JavaScript code immediately before using .append()
// or the like to load the remote script.
document.write = function() {
    // document.write can take multiple arguments, so concatenate them.
    var text = Array.prototype.slice.call( arguments ).join( '' );
    // Now text is what would have been written by document.write().
    // Use a DOM/jQuery/etc. call here to insert it into your page.
};
// Here is where you will load the remote script

Now when the remote script calls document.write() it will really be calling your function, so you can handle it as you want.

Wouldn't replacing document.write() like this possibly break other code that works and uses it legitimately? No, because any such working code would have run during page load time, otherwise it would already be broken. You don't replace the function until later, when the page has been fully loaded.

The main risk would be if other code you're loading also uses this same trick. Their document.write() replacement and yours could step on each other.

Upvotes: 3

Related Questions