109

I include myscript.js in the file http://site1.com/index.html like this:

<script src=http://site2.com/myscript.js></script>

Inside "myscript.js", I want to get access to the URL "http://site2.com/myscript.js". I'd like to have something like this:

function getScriptURL() {
    // something here
    return s
}

alert(getScriptURL());

Which would alert "http://site2.com/myscript.js" if called from the index.html mentioned above.

4

10 Answers 10

75

Everything except IE supports

document.currentScript

Eg

document.currentScript.src
Sign up to request clarification or add additional context in comments.

3 Comments

More precisely: document.currentScript.src.
A word of caution! it will not work if the loaded is script type is module. for more stackoverflow.com/questions/2976651/…
62

From http://feather.elektrum.org/book/src.html:

var scripts = document.getElementsByTagName('script');
var index = scripts.length - 1;
var myScript = scripts[index];

The variable myScript now has the script dom element. You can get the src url by using myScript.src.

Note that this needs to execute as part of the initial evaluation of the script. If you want to not pollute the Javascript namespace you can do something like:

var getScriptURL = (function() {
    var scripts = document.getElementsByTagName('script');
    var index = scripts.length - 1;
    var myScript = scripts[index];
    return function() { return myScript.src; };
})();

18 Comments

Will this always return the URL of the right script though, in all browsers? This looks like it will return the last script tag, but what if the document has more than one script tag in it?
Ok...my question then becomes, do all browsers always fully load an execute the complete contents of a remote script before moving on to the next script tag? How rigorously is this standardized? I could imagine it happening in parallel...
It is required that scripts run completely and in order because of what would happen if the script tag contained a document.write. This is the reason for the recommendations to put scripts at the bottom of the page because they will actually block other content from loading. That said, HTML5 modifies that with the use of the async and defer attributes: whatwg.org/specs/web-apps/current-work/multipage/…
This doesn't work if you load the script after the page has loaded using something like this: document.getElementsByTagName("head")[0].appendChild(scriptElement);
I have come across a case where this algorithm doesn't work reliably. Other script tags that are set to async can run between your script being requested and run. These scripts can add other scripts to the DOM which appear after yours. When your script run the last script on the page is no longer yours and the wrong src is returned.
|
62

You can add id attribute to your script tag (even if it is inside a head tag):

<script id="myscripttag" src="http://site2.com/myscript.js"></script>

and then access to its src as follows:

document.getElementById("myscripttag").src

of course id value should be the same for every document that includes your script, but I don't think it is a big inconvenience for you.

2 Comments

This answer should be marked as "accepted" as it covers the cases when you call the method not in the "global" script context or in "async" script, and it doesn't depend on the browser implementation.
Note that .src can return an absolute path, even if a relative path was specified. You can use .getAttribute('src')
30

Simple and straightforward solution that work very well :

If it not IE you can use document.currentScript
For IE you can do document.querySelector('script[src*="myscript.js"]')
so :

function getScriptURL(){
 var script =  document.currentScript || document.querySelector('script[src*="myscript.js"]')
 return script.src
}
update

In a module script, you can use:

 import.meta.url

as describe in mdn

Comments

20

I wrote a class to find get the path of scripts that works with delayed loading and async script tags.

I had some template files that were relative to my scripts so instead of hard coding them I made created the class to do create the paths automatically. The full source is here on github.

A while ago I had use arguments.callee to try and do something similar but I recently read on the MDN that it is not allowed in strict mode.

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}

7 Comments

A bit late to the party here, but I was trying this code snippet and found that the part where it adds 2 to the current index in the for loop "callerIndex = Number(i) + 2;" seems to break be unnecessary and causes it to not work. Simply eliminating the "+ 2" has it working. Is there something I am misinterpreting or some other scenario that that + 2 would be necessary for?
you don't need to throw "Error" this way ( to get it's ".stack" ) it is just an object like others: console.log( new Error().stack );
Thanks for this idea, and thanks to @AbdullahAydın for the idea of preventing a throw. Then I guess the following one-liner would do the trick, wouldn't it? var scriptUrl = new Error().stack.match(/@(https?:\/\/.+):\d+:\d+/)[1]
Also @Pierre-Antoine keep in mind that Error.prototype.stack property is non-standard :/ you should use it with care. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@AbdullahAydın: Note that the stack property of a new error is not populated in the IE and Edge browsers until the error is thrown.
|
15

if you have a chance to use jQuery, the code would look like this:

$('script[src$="/myscript.js"]').attr('src');

3 Comments

Does it work with defer, async and lazy loading scripts?
It's just looking through the DOM for a script tag with the src "/myscript.js". other attributes won't matter
To use this with wordpress to in any other place that appends the version you should use $('script[src*="/myscript.js"]').attr('src'); this way it will ignore the ?ver=2.3.3 at the end of the script. The * will keep it working regardless of what is at the end.
3
document.currentScript.src

will return the URL of the current Script URL.

Note: If you have loaded the script with type Module then use

import.meta.url

for more import.meta & currentScript.src

Comments

2

Following code lets you find the script element with given name

var scripts = document.getElementsByTagName( 'script' );
        var len = scripts.length
        for(var i =0; i < len; i++) {
            if(scripts[i].src.search("<your JS file name") > 0 && scripts[i].src.lastIndexOf("/") >= 0) {
                absoluteAddr = scripts[i].src.substring(0, scripts[i].src.lastIndexOf("/") + 1);
                break;
            }
        }

1 Comment

It seems that using querySelector() would be a bit shorter and probably quicker nowadays.
0

Some necromancy, but here's a function that tries a few methods

function getScriptPath (hint) {
    if (  typeof document === "object" && 
          typeof document.currentScript === 'object' && 
          document.currentScript && // null detect
          typeof document.currentScript.src==='string' && 
          document.currentScript.src.length > 0) {
        return document.currentScript.src;
    }
    
    
    let here = new Error();
    if (!here.stack) {
        try { throw here;} catch (e) {here=e;}
    }
    if (here.stack) {
        
        const stacklines = here.stack.split('\n');
        console.log("parsing:",stacklines);
        let result,ok=false;
        stacklines.some(function(line){
            if (ok) {
               const httpSplit=line.split(':/');
               const linetext = httpSplit.length===1?line.split(':')[0]:httpSplit[0]+':/'+( httpSplit.slice(1).join(':/').split(':')[0]);
               const chop = linetext.split('at ');
               if (chop.length>1) {
                   result = chop[1];
                   if ( result[0]!=='<') {
                      console.log("selected script from stack line:",line);               
                      return true;
                   }
                   result=undefined;
               }
               return false; 
            }
            ok = line.indexOf("getScriptPath")>0;
            return false;
        });
        return result;
    }
    
    if ( hint && typeof document === "object") {
       const script = document.querySelector('script[src="'+hint+'"]');
       return script && script.src && script.src.length && script.src;
    }
    
}
   
   console.log("this script is at:",getScriptPath ())

Comments

-6

Can't you use location.href or location.host and then append the script name?

2 Comments

That won't work, because the script is running within the site1.com/index.html page. So, even through the script is loaded from site2.com, if you access location from within the script, it will return "site1.com/index.html"...
Previous comment might not make it clear enough, but location.href is the URL of current page. The script will probably be located in some sub-directory like /scripts/script.js or could even be an external one. If there is a need to get the URL of the current script, then there is generally a serious reason for that and it really and simple page URL will not be of any help.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.