Related
I want to dynamically include a script tag in a webpage however I have no control of it's src so src="source.js" may look like this.
document.write('<script type="text/javascript">')
document.write('alert("hello world")')
document.write('</script>')
document.write('<p>goodbye world</p>')
Now ordinarily putting
<script type="text/javascript" src="source.js"></script>
In the head works fine but is there any other way I can add source.js dynamically using something like innerHTML?
jsfiddle of what i've tried
var my_awesome_script = document.createElement('script');
my_awesome_script.setAttribute('src','http://example.com/site.js');
document.head.appendChild(my_awesome_script);
You can use the document.createElement() function like this:
function addScript( src ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
document.body.appendChild( s );
}
There is the onload function, that could be called when the script has loaded successfully:
function addScript( src, callback ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
s.onload=callback;
document.body.appendChild( s );
}
It's almost a decade later and nobody bothers to write the Promise version, so here is mine (based on this awnser):
function addScript(src) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.setAttribute('src', src);
s.addEventListener('load', resolve);
s.addEventListener('error', reject);
document.body.appendChild(s);
});
}
Usage
try {
await addScript('https://api.stackexchange.com/js/2.0/all.js');
// do something after it was loaded
} catch (e) {
console.log(e);
}
a nice little script I wrote to load multiple scripts:
function scriptLoader(scripts, callback) {
var count = scripts.length;
function urlCallback(url) {
return function () {
console.log(url + ' was loaded (' + --count + ' more scripts remaining).');
if (count < 1) {
callback();
}
};
}
function loadScript(url) {
var s = document.createElement('script');
s.setAttribute('src', url);
s.onload = urlCallback(url);
document.head.appendChild(s);
}
for (var script of scripts) {
loadScript(script);
}
};
usage:
scriptLoader(['a.js','b.js'], function() {
// use code from a.js or b.js
});
When scripts are loaded asynchronously they cannot call document.write. The calls will simply be ignored and a warning will be written to the console.
You can use the following code to load the script dynamically:
var scriptElm = document.createElement('script');
scriptElm.src = 'source.js';
document.body.appendChild(scriptElm);
This approach works well only when your source belongs to a separate file.
But if you have source code as inline functions which you want to load dynamically and want to add other attributes to the script tag, e.g. class, type, etc., then the following snippet would help you:
var scriptElm = document.createElement('script');
scriptElm.setAttribute('class', 'class-name');
var inlineCode = document.createTextNode('alert("hello world")');
scriptElm.appendChild(inlineCode);
document.body.appendChild(scriptElm);
You can try following code snippet.
function addScript(attribute, text, callback) {
var s = document.createElement('script');
for (var attr in attribute) {
s.setAttribute(attr, attribute[attr] ? attribute[attr] : null)
}
s.innerHTML = text;
s.onload = callback;
document.body.appendChild(s);
}
addScript({
src: 'https://www.google.com',
type: 'text/javascript',
async: null
}, '<div>innerHTML</div>', function(){});
A one-liner (no essential difference to the answers above though):
document.body.appendChild(document.createElement('script')).src = 'source.js';
This Is Work For Me.
You Can Check It.
var script_tag = document.createElement('script');
script_tag.setAttribute('src','https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js');
document.head.appendChild(script_tag);
window.onload = function() {
if (window.jQuery) {
// jQuery is loaded
alert("ADD SCRIPT TAG ON HEAD!");
} else {
// jQuery is not loaded
alert("DOESN'T ADD SCRIPT TAG ON HEAD");
}
}
Loads scripts that depends on one another with the right order.
Based on Satyam Pathak response, but fixed the onload.
It was triggered before the script actually loaded.
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = () => recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Well, there are multiple ways you can include dynamic javascript,
I use this one for many of the projects.
var script = document.createElement("script")
script.type = "text/javascript";
//Chrome,Firefox, Opera, Safari 3+
script.onload = function(){
console.log("Script is loaded");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
You can call create a universal function which can help you to load as many javascript files as needed. There is a full tutorial about this here.
Inserting Dynamic Javascript the right way
No one mentioned it, but you can also stick the actual source code into a script tag by making a URL out of it using URL and Blob:
const jsCode = `
// JS code in here. Maybe you extracted it from some HTML string.
`
const url = URL.createObjectURL(new Blob([jsCode]))
const script = document.createElement('script')
script.src = url
URL.revokeObjectURL(url) // dispose of it when done
as for the jsCode, you may have gotten it from some HTML.
Here's a more full example of how you'd handle any number of scripts in an HTML source:
main()
async function main() {
const scriptTagOpen = /<script\b[^>]*>/g
const scriptTagClose = /<\/script\b[^>]*>/g
const scriptTagRegex = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const response = await fetch('path/to/some.html')
const html = await response.text()
someElement.innerHTML = html
// We need to get the script tags and manually add them to DOM
// because otherwise innerHTML will not execute them.
const codes =
html
.match(scriptTagRegex)
?.map(code => code.replace(scriptTagOpen, '').replace(scriptTagClose, ''))
.map(code => URL.createObjectURL(new Blob([code]))) || []
for (const code of codes) {
const script = document.createElement('script')
script.src = code
someElement.append(script)
URL.revokeObjectURL(code)
}
}
the only way to do this is to replace document.write with your own function which will append elements to the bottom of your page. It is pretty straight forward with jQuery:
document.write = function(htmlToWrite) {
$(htmlToWrite).appendTo('body');
}
If you have html coming to document.write in chunks like the question example you'll need to buffer the htmlToWrite segments. Maybe something like this:
document.write = (function() {
var buffer = "";
var timer;
return function(htmlPieceToWrite) {
buffer += htmlPieceToWrite;
clearTimeout(timer);
timer = setTimeout(function() {
$(buffer).appendTo('body');
buffer = "";
}, 0)
}
})()
I tried it by recursively appending each script
Note If your scripts are dependent one after other, then position will need to be in sync.
Major Dependency should be in last in array so that initial scripts can use it
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Here is a minified snippet, same code as Google Analytics and Facebook Pixel uses:
!function(e,s,t){(t=e.createElement(s)).async=!0,t.src="https://example.com/foo.js",(e=e.getElementsByTagName(s)[0]).parentNode.insertBefore(t,e)}(document,"script");
Replace https://example.com/foo.js with your script path.
window.addEventListener("load", init);
const loadScript = async (url) => {
const response = await fetch(url);
const script = await response.text();
eval(script);
}
function init() {
const wistiaVideo = document.querySelector(".wistia_embed");
if ("IntersectionObserver" in window && "IntersectionObserverEntry" in window && "intersectionRatio" in window.IntersectionObserverEntry.prototype) {
let lazyVideoObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
setTimeout(() => loadScript("//fast.wistia.com/assets/external/E-v1.js"), 1000);
lazyVideoObserver.unobserve(entry.target);
console.log("E-v1.js script loaded from fast.wistia.com");
}
});
});
lazyVideoObserver.observe(wistiaVideo);
}
}
<div style="height: 150vh; background-color: #f7f7f7;"></div>
<h1>Wistia Video!</h1>
<div class="wistia_embed wistia_async_29b0fbf547" style="width:640px;height:360px;"> </div>
<h1>Video Ended!</h1>
I want to dynamically include a script tag in a webpage however I have no control of it's src so src="source.js" may look like this.
document.write('<script type="text/javascript">')
document.write('alert("hello world")')
document.write('</script>')
document.write('<p>goodbye world</p>')
Now ordinarily putting
<script type="text/javascript" src="source.js"></script>
In the head works fine but is there any other way I can add source.js dynamically using something like innerHTML?
jsfiddle of what i've tried
var my_awesome_script = document.createElement('script');
my_awesome_script.setAttribute('src','http://example.com/site.js');
document.head.appendChild(my_awesome_script);
You can use the document.createElement() function like this:
function addScript( src ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
document.body.appendChild( s );
}
There is the onload function, that could be called when the script has loaded successfully:
function addScript( src, callback ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
s.onload=callback;
document.body.appendChild( s );
}
It's almost a decade later and nobody bothers to write the Promise version, so here is mine (based on this awnser):
function addScript(src) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.setAttribute('src', src);
s.addEventListener('load', resolve);
s.addEventListener('error', reject);
document.body.appendChild(s);
});
}
Usage
try {
await addScript('https://api.stackexchange.com/js/2.0/all.js');
// do something after it was loaded
} catch (e) {
console.log(e);
}
a nice little script I wrote to load multiple scripts:
function scriptLoader(scripts, callback) {
var count = scripts.length;
function urlCallback(url) {
return function () {
console.log(url + ' was loaded (' + --count + ' more scripts remaining).');
if (count < 1) {
callback();
}
};
}
function loadScript(url) {
var s = document.createElement('script');
s.setAttribute('src', url);
s.onload = urlCallback(url);
document.head.appendChild(s);
}
for (var script of scripts) {
loadScript(script);
}
};
usage:
scriptLoader(['a.js','b.js'], function() {
// use code from a.js or b.js
});
When scripts are loaded asynchronously they cannot call document.write. The calls will simply be ignored and a warning will be written to the console.
You can use the following code to load the script dynamically:
var scriptElm = document.createElement('script');
scriptElm.src = 'source.js';
document.body.appendChild(scriptElm);
This approach works well only when your source belongs to a separate file.
But if you have source code as inline functions which you want to load dynamically and want to add other attributes to the script tag, e.g. class, type, etc., then the following snippet would help you:
var scriptElm = document.createElement('script');
scriptElm.setAttribute('class', 'class-name');
var inlineCode = document.createTextNode('alert("hello world")');
scriptElm.appendChild(inlineCode);
document.body.appendChild(scriptElm);
You can try following code snippet.
function addScript(attribute, text, callback) {
var s = document.createElement('script');
for (var attr in attribute) {
s.setAttribute(attr, attribute[attr] ? attribute[attr] : null)
}
s.innerHTML = text;
s.onload = callback;
document.body.appendChild(s);
}
addScript({
src: 'https://www.google.com',
type: 'text/javascript',
async: null
}, '<div>innerHTML</div>', function(){});
A one-liner (no essential difference to the answers above though):
document.body.appendChild(document.createElement('script')).src = 'source.js';
This Is Work For Me.
You Can Check It.
var script_tag = document.createElement('script');
script_tag.setAttribute('src','https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js');
document.head.appendChild(script_tag);
window.onload = function() {
if (window.jQuery) {
// jQuery is loaded
alert("ADD SCRIPT TAG ON HEAD!");
} else {
// jQuery is not loaded
alert("DOESN'T ADD SCRIPT TAG ON HEAD");
}
}
Loads scripts that depends on one another with the right order.
Based on Satyam Pathak response, but fixed the onload.
It was triggered before the script actually loaded.
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = () => recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Well, there are multiple ways you can include dynamic javascript,
I use this one for many of the projects.
var script = document.createElement("script")
script.type = "text/javascript";
//Chrome,Firefox, Opera, Safari 3+
script.onload = function(){
console.log("Script is loaded");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
You can call create a universal function which can help you to load as many javascript files as needed. There is a full tutorial about this here.
Inserting Dynamic Javascript the right way
No one mentioned it, but you can also stick the actual source code into a script tag by making a URL out of it using URL and Blob:
const jsCode = `
// JS code in here. Maybe you extracted it from some HTML string.
`
const url = URL.createObjectURL(new Blob([jsCode]))
const script = document.createElement('script')
script.src = url
URL.revokeObjectURL(url) // dispose of it when done
as for the jsCode, you may have gotten it from some HTML.
Here's a more full example of how you'd handle any number of scripts in an HTML source:
main()
async function main() {
const scriptTagOpen = /<script\b[^>]*>/g
const scriptTagClose = /<\/script\b[^>]*>/g
const scriptTagRegex = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const response = await fetch('path/to/some.html')
const html = await response.text()
someElement.innerHTML = html
// We need to get the script tags and manually add them to DOM
// because otherwise innerHTML will not execute them.
const codes =
html
.match(scriptTagRegex)
?.map(code => code.replace(scriptTagOpen, '').replace(scriptTagClose, ''))
.map(code => URL.createObjectURL(new Blob([code]))) || []
for (const code of codes) {
const script = document.createElement('script')
script.src = code
someElement.append(script)
URL.revokeObjectURL(code)
}
}
the only way to do this is to replace document.write with your own function which will append elements to the bottom of your page. It is pretty straight forward with jQuery:
document.write = function(htmlToWrite) {
$(htmlToWrite).appendTo('body');
}
If you have html coming to document.write in chunks like the question example you'll need to buffer the htmlToWrite segments. Maybe something like this:
document.write = (function() {
var buffer = "";
var timer;
return function(htmlPieceToWrite) {
buffer += htmlPieceToWrite;
clearTimeout(timer);
timer = setTimeout(function() {
$(buffer).appendTo('body');
buffer = "";
}, 0)
}
})()
I tried it by recursively appending each script
Note If your scripts are dependent one after other, then position will need to be in sync.
Major Dependency should be in last in array so that initial scripts can use it
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Here is a minified snippet, same code as Google Analytics and Facebook Pixel uses:
!function(e,s,t){(t=e.createElement(s)).async=!0,t.src="https://example.com/foo.js",(e=e.getElementsByTagName(s)[0]).parentNode.insertBefore(t,e)}(document,"script");
Replace https://example.com/foo.js with your script path.
window.addEventListener("load", init);
const loadScript = async (url) => {
const response = await fetch(url);
const script = await response.text();
eval(script);
}
function init() {
const wistiaVideo = document.querySelector(".wistia_embed");
if ("IntersectionObserver" in window && "IntersectionObserverEntry" in window && "intersectionRatio" in window.IntersectionObserverEntry.prototype) {
let lazyVideoObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
setTimeout(() => loadScript("//fast.wistia.com/assets/external/E-v1.js"), 1000);
lazyVideoObserver.unobserve(entry.target);
console.log("E-v1.js script loaded from fast.wistia.com");
}
});
});
lazyVideoObserver.observe(wistiaVideo);
}
}
<div style="height: 150vh; background-color: #f7f7f7;"></div>
<h1>Wistia Video!</h1>
<div class="wistia_embed wistia_async_29b0fbf547" style="width:640px;height:360px;"> </div>
<h1>Video Ended!</h1>
Without using any external library how can I wait for a script to load before using it.
In my case I'm loading the scripts using:
(function (w,d,t,s,e,r) {
e = d.createElement(o);
r = d.getElementsByTagName(o)[0];
e.async = 1;
e.src = g;
r.parentNode.insertBefore(e, r)
})(window, document, 'script', '//mydomain.com/path/to/script.js');
And later:
// then later I want to use some code form the script:
var obj = new classFromTheInjectedScript();
Is there away to wait for the script to load and then start using it?
Note: I have a way that I can trigger an event within the script I want
to load and then listen to it as you can see below, but is this a good idea?
(function(w,d){
document.addEventListener('scriptLoadedCustomEvent',onScriptReady);
function onScriptReady(){
// what I need to do goes here!
}
})(window,document);
You should be able to do something like this!
var script = document.createElement('script');
script.src = url; //source
var callback = function (){
// do stuff after loaded
}
script.onload = callback;
document.head.appendChild(script); //inject where you need it to be
You can use onload and onerror events for <script> tag. Good example here.
Here is a function that would be help to load a script and on successful load.. you can wait and perform your actions
function loadScript(url) {
const w = window;
const d = document;
const l = () => {
const s = d.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = url;
const x = d.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
s.addEventListener('load', () => {
// This loads the script
yourFunctionAfterScriptLoaded();
});
};
if (w.attachEvent) {
w.attachEvent('onload', l);
} else {
w.addEventListener('load', l, false);
}
}
or you can directly use the script onload function as shown in this link
you could read the file source and inserting it in a script tag manually, so you will have the AJAX response event
I am new to jquery. I am trying to append Jquery in an HTML page in java. To include jquery.js file I have written following code:
scriptTag += "var script = document.createElement('script');" +
"script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'; " +
"script.type = 'text/javascript'; " +
"document.getElementsByTagName('head')[0].appendChild(script);" +
and then I appended following js+jquery code with it
"var script2 = document.createElement('script'); window.onload = function() {" +
"$(document).ready(function() {" +
"$(\"#identity\").hide();});};" +
"script2.type = 'text/javascript'; " +
"document.getElementsByTagName('head')[0].appendChild(script2);";
So basically I am trying to write this :
var script = document.createElement('script');
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
var script2 = document.createElement('script');
window.onload = function() {
$(document).ready(function() {
$("#identity").hide();
});
};
script2.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script2);
What I want to do is that I want my function after window load. Somehow, writing $(document).ready(function() { alone does'nt work. I get an error that $ is not defined (looks like jquery.js is not ready yet).
To avoid this problem I have used window.onload = function() {. But now I am getting error: $(document).ready is not a function. I am really confused here on how to write this thing. Is this the correct approach? Any help/guidance is highly appreciated.
[Edit]
Please note that the following code (without jquery) works fine:
window.onload = function() {
document.getElementById('identity').style.visibility='hidden';
};
[Edit]
Actually I am making a web proxy, where I download page and serve them with custom look and field. The pages does not contain any jquery files nor can I include or write HTML. I can only add my Js dynamically using java etc.
Here is some code that shows how to load a script file dynamically and also delay calling of $(document).ready until that file is loaded:
http://jqfaq.com/how-to-load-java-script-files-dynamically/
The code you use to load jquery.min.js file is called asycnhroniously. Probably this file has not been loaded at the moment you try to execute jquery function.
Therefore you should make sure that the file is loaded using a callback function.
In the following link you can find an example on how to this:
http://blog.logiclabz.com/javascript/dynamically-loading-javascript-file-with-callback-event-handlers.aspx
Also here is a working example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>index</title>
<script type="text/javascript">
function loadScript(sScriptSrc, callbackfunction) {
//gets document head element
var oHead = document.getElementsByTagName('head')[0];
if (oHead) {
//creates a new script tag
var oScript = document.createElement('script');
//adds src and type attribute to script tag
oScript.setAttribute('src', sScriptSrc);
oScript.setAttribute('type', 'text/javascript');
//calling a function after the js is loaded (IE)
var loadFunction = function() {
if (this.readyState == 'complete' || this.readyState == 'loaded') {
callbackfunction();
}
};
oScript.onreadystatechange = loadFunction;
//calling a function after the js is loaded (Firefox)
oScript.onload = callbackfunction;
//append the script tag to document head element
oHead.appendChild(oScript);
}
}
var SuccessCallback = function() {
$("#identity").hide();
}
window.onload = function() {
loadScript('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', SuccessCallback)
};
</script>
</head>
<body>
<span id="identity"> This text will be hidden after SuccessCallback </span>
</body>
You should use this code in your scriptTag variable and then you can use eval() function to evaluate the script in this variable. Also you can load the second javascript file in the callback function using jquery's getscript function
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Include a JavaScript file in a JavaScript file
How to include a JavaScript file in another JavaScript file?
What is the best way to import a JavaScript file, for example file.js, in a JavaScript function()?
For example, what is the best way to replace the todo statement:
function doSomething() {
if (xy.doSomething == undefined) {
// TODO: load 'oldVersionPatch.js'
}
...
}
Possibly the best solution is to create script element and add it into the HTML page.
Is it better to add/append it into head, or body (what will load when)?
Is it better to use JavaScript or jQuery (what is more cross-browser compatible)?
http://api.jquery.com/jQuery.getScript/
or
(function(){
this.__defineGetter__("__FILE__", function() {
return (new Error).stack.split("\n")[2].split("#")[1].split(":").slice(0,-1).join(":");
});
})();
(function(){
this.__defineGetter__("__DIR__", function() {
return __FILE__.substring(0, __FILE__.lastIndexOf('/'));
});
})();
function include(file,charset) {
if (document.createElement && document.getElementsByTagName) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', __DIR__ + '/' + file);
if(charset){
script.setAttribute('charset', charset);
}
head.appendChild(script);
}
}
var filename = 'oldVersionPatch.js';
var js = document.createElement('script');
js.setAttribute("type","text/javascript");
js.setAttribute("src", filename);
document.getElementsByTagName("head")[0].appendChild(js);
.. should do it
Very simply, in JavaScript create a <script> element, append the src attribute with whatever the URL is and attach to the DOM. That should do it.
You have to make your code asynchronous to gain this:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = yourJavascriptFileLocation;
script.onload = script.onreadystatechange = function() {
if (!script.readyState || script.readyState === 'complete') {
/* Your code rely on this JavaScript code */
}
};
var head = document.getElementsByTagName('head')[0];
// Don't use appendChild
head.insertBefore(script, head.firstChild);