62

I'm pretty sure the answer is no, but thought I'd ask anyway.

If my site references a scripted named "whatever.js", is it possible to get "whatever.js" from within that script? Like:

var scriptName = ???

if (typeof jQuery !== "function") {
    throw new Error(
        "jQuery's script needs to be loaded before " + 
        scriptName + ". Check the <script> tag order.");
}

Probably more trouble than it's worth for dependency checking, but what the hell.

Shog9
  • 156,901
  • 35
  • 231
  • 235
core
  • 32,451
  • 45
  • 138
  • 193
  • Since you are going to be typing that line into the file somewhere, couldn't you just type in the name of the file you're adding it to? – MarkusQ Apr 02 '09 at 18:22
  • Yeah, that works, unless the filename is changed. I'm probably just being too pedantic. – core Apr 02 '09 at 18:24
  • Heh, if someone wants to submit "fuss less" and that gets a couple upvotes, I'd accept that as the answer. :D – core Apr 02 '09 at 18:26
  • Specifying 'var scriptName = ...' inside each script probably isn't the greatest idea. The way you are declaring it, scriptName is a global variable. It would work better if you used closures. http://www.jibbering.com/faq/faq%5Fnotes/closures.html – Sebastian Celis Apr 02 '09 at 18:30
  • 3
    The other advantage to this is if you want to get the full URL-path to the running script. Not all .js files are served from the same domain as the html pages that use them. – Ed Brannin Oct 28 '09 at 19:55
  • See also [Get script path](http://stackoverflow.com/questions/2161159/get-script-path) and [What is my script src URL?](http://stackoverflow.com/questions/984510/what-is-my-script-src-url) – Bergi Jul 17 '13 at 15:44
  • I'd love to see something that works with PhantomJS – William Entriken May 01 '14 at 16:48

12 Answers12

40
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
var scriptName = lastScript.src;
alert("loading: " + scriptName);

Tested in: FF 3.0.8, Chrome 1.0.154.53, IE6


See also: How may I reference the script tag that loaded the currently-executing script?

Community
  • 1
  • 1
Shog9
  • 156,901
  • 35
  • 231
  • 235
  • 7
    Edge case: If the current script was added to `` after `` is loaded and there are any scripts in `` this will return the last script in the ``, not the currently running script that's in ``. – Nate Oct 07 '13 at 21:11
  • 11
    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. – Karl Oct 09 '13 at 12:42
  • 5
    This answer is seriously out of date. Scripts can be deferred, async, modules, workers. This answer works in none of them. – gman Jan 30 '19 at 06:52
  • 1
    I feel like `document.currentScript` should be mentioned here, but like @gman said this answer is out of date overall and the algorithm does not cover many edge cases. – Tomáš Hübelbauer Aug 12 '20 at 16:07
27

I'm aware this is old but I have developed a better solution because all of the above didn't work for Async scripts. With some tweaking the following script can cover almost all use cases. Heres what worked for me:

function getScriptName() {
    var error = new Error()
      , source
      , lastStackFrameRegex = new RegExp(/.+\/(.*?):\d+(:\d+)*$/)
      , currentStackFrameRegex = new RegExp(/getScriptName \(.+\/(.*):\d+:\d+\)/);

    if((source = lastStackFrameRegex.exec(error.stack.trim())) && source[1] != "")
        return source[1];
    else if((source = currentStackFrameRegex.exec(error.stack.trim())))
        return source[1];
    else if(error.fileName != undefined)
        return error.fileName;
}

Not sure about support on Internet Explorer, but works fine in every other browser I tested on.

jduncanator
  • 2,154
  • 1
  • 22
  • 39
  • Thanks! Exactly what I was looking for! Interesting that sometimes the same approach with error's stack appears in python or Java code. – scythargon Feb 22 '14 at 01:32
  • 4
    Thanks! that's a great approach as it works also in Web Workers. However it fails after minification because the function is not called getScriptName anymore. The solution is to replace the currentStackFrameRegex expression with: new RegExp(arguments.callee.name + ' \\(.+\\/(.*):\\d+:\\d+\\)') – MaMazav May 06 '15 at 17:32
  • 1
    Very nice solution, sadly it does not work on IE10- :( – psychowood May 27 '15 at 18:13
  • @PsychoWood I'll take a look and update the answer if I find a solution. – jduncanator May 28 '15 at 10:08
  • I see that I get the second line for `currentStackFrameRegex` but for me `source[1]` is an empty string. – Asken Nov 26 '15 at 12:35
  • It would be better to detect `document.currentScript` before doing the workaround. – alex Mar 24 '16 at 15:13
  • 1
    @MaMazav `arguments.callee.name` won't work If the function is defined as a function expression. I think the catch-all solution would be replacing `arguments.callee.name` with `scriptName` where `scriptName` is `var scriptName = arguments.callee.name || 'getScriptName';`. Of course, minification would change the variable name if the function expression is assigned to a normal variable, so one would have to assign the function to an object key to make this work. – Michael Mar 26 '16 at 06:08
  • @Michael Another simpler solution would be to disable minification of that symbol. – jduncanator Mar 29 '16 at 00:32
  • Update: On current Firefox version the above code doesn't work for me. I added another regex which caught the new case: /.+@(.*?):\d+:\d+/ (tested on ff 57). – MaMazav Nov 18 '17 at 21:07
  • This looks very fragile and can potentially introduce performance issues or catastrophic backtracking depending on how your code looks. I would avoid this at almost all costs, or at least careful consider the importance in contrast to the potential implications of this. – Mathias Lykkegaard Lorenzen Jan 03 '19 at 12:50
  • @MathiasLykkegaardLorenzen Things that can't be done out of the box, and are complex to achieve, usually are fairly fragile. That said, I've been using this snippet (or at least a variation of it) for the last 4 years on a number of sites and it is still working fine. YMMV. – jduncanator Jan 07 '19 at 22:22
20

You can use...

var scripts = document.getElementsByTagName("script"),
  currentScriptUrl = (document.currentScript || scripts[scripts.length - 1]).src;

currentScript() is supported by all browsers except IE.

Make sure it's ran as the file is parsed and executed, not on DOM ready or window load.

If it's an empty string, your script block has no or an empty src attribute.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    Not directly related to answer, but the famous http://caniuse.com doesn't monitor `document.currentScript` yet. An issue has been opened however. To make this feature appear on caniuse.com, you can vote up: https://github.com/Fyrd/caniuse/issues/1099. – Stephan Mar 24 '16 at 15:12
  • 2
    I like that this is useful even in `async` scripts, unlike some other answers. Unfortunately, if `currentScript` is called in an event handler or global function that itself is called from another file, it will return that other file. – trysis Nov 23 '16 at 17:15
  • 3
    Further to the comment by @Stephan, there is now an entry for [document.currentScript](https://caniuse.com/#feat=document-currentscript) at caniuse.com. – faintsignal Mar 28 '18 at 19:48
9

In Node.js:

var abc = __filename.split(__dirname+"/").pop();
Jose Gómez
  • 3,110
  • 2
  • 32
  • 54
Alichino
  • 1,668
  • 2
  • 16
  • 25
5

Shog9's suggestion more shorter:

alert("loading: " + document.scripts[document.scripts.length-1].src);
F-3000
  • 935
  • 13
  • 13
3

You can return a list of script elements in the page:

var scripts = document.getElementsByTagName("script");

And then evaluate each one and retrieve its location:

var location;

for(var i=0; i<scripts.length;++i) {
   location = scripts[i].src;

   //Do stuff with the script location here
}
Alex Rozanski
  • 37,815
  • 10
  • 68
  • 69
2

As the "src" attribute holds the full path to the script file you can add a substring call to get the file name only.

var path = document.scripts[document.scripts.length-1].src;

var fileName = path.substring(path.lastIndexOf('/')+1);
1

I had issues with the above code while extracting the script name when the calling code is included inside a .html file. Hence I developed this solution:

var scripts = document.getElementsByTagName( "script" ) ;
var currentScriptUrl = ( document.currentScript || scripts[scripts.length - 1] ).src ;
var scriptName = currentScriptUrl.length > 0 ? currentScriptUrl : scripts[scripts.length-1].baseURI.split( "/" ).pop() ; 
Sandro Rosa
  • 507
  • 4
  • 12
1

You can try putting this at the top of your JavaScript file:

window.myJSFilename = "";
window.onerror = function(message, url, line) {
    if (window.myJSFilename != "") return;
    window.myJSFilename =  url;
}
throw 1;

Make sure you have only functions below this. The myJSFilename variable will contain the full path of the JavaScript file, the filename can be parsed from that. Tested in IE11, but it should work elsewhere.

1

If you did't want use jQuery:

function getCurrentFile() {
    var filename = document.location.href;
    var tail = (filename.indexOf(".", (filename.indexOf(".org") + 1)) == -1) ? filename.length : filename.lastIndexOf(".");
    return (filename.lastIndexOf("/") >= (filename.length - 1)) ? (filename.substring(filename.substring(0, filename.length - 2).lastIndexOf("/") + 1, filename.lastIndexOf("/"))).toLowerCase() : (filename.substring(filename.lastIndexOf("/") + 1, tail)).toLowerCase();
}
JoseLazo
  • 208
  • 2
  • 5
0

The only way that is waterproof:

var code = this.__proto__.constructor.toString();
$("script").each(function (index, element) {
    var src = $(element).attr("src");
    if (src !== undefined) {
        $.get(src, function (data) {
            if (data.trim() === code) {
                scriptdir = src.substring(0, src.lastIndexOf("/"));
            }
        });
    }
});

"var code" can also be the function name, but with the prototype constructor you don't have to modify anything. This code compares its own content against all present scripts. No hard coded filenames needed anymore. Korporal Nobbs was in the right direction, but not complete with the comparison.

0

What will happen if the jQuery script isn't there? Are you just going to output a message? I guess it is slightly better for debugging if something goes wrong, but it's not very helpful for users.

I'd say just design your pages such that this occurrence will not happen, and in the rare event it does, just let the script fail.

DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
  • 1
    Yes, I throw new Error() with a "include the script dumbass!" message. My feeling is that it's just good practice. People tend to slack on things like this because it's a dynamic language. I'll sleep better this way though. The extra 100 bytes are worth it to me. :) – core Apr 04 '09 at 09:25