If–within a javascript file–you wish to find the path to this file, how’s it done?

Javascript provides helpful objects like self.location that can be used to find the URL of the page running the script but I was completely unable to find an object representing the path to the current script. This is useful when creating a plugin for distribution to other users in which there is no control over the folder the user will put the plugin in. It’s a lot easier to say to people “put all these files in the same folder” than it is to say “put all these files in a folder /scripts/foo/bar/” because your user might not have that much control.

Assume we have a file script.js that needs to load some other resources flash.swf and image.png. The file script.js is in the directory foo/bar appearing therefore at the URL http://www.example.com/foo/bar/script.js. Also, we assume this script is loaded via a <script type="text/javascript" src="/foo/bar/script.js"></script> from an HTML file that could be anywhere in the website. We can use the following function to extract the /foo/bar/ from the above script statement:

var scriptPath = function () {
    var scripts = document.getElementsByTagName('SCRIPT');
    var path = '';
    if(scripts && scripts.length>0) {
        for(var i in scripts) {
            if(scripts[i].src && scripts[i].src.match(/\/script\.js$/)) {
                path = scripts[i].src.replace(/(.*)\/script\.js$/, '$1');
                break;
            }
        }
    }
    return path;
};

This function basically scans the DOM tree for all the script tags and looks for the one with the same name as the script we’re currently executing. This has to be hard-coded, unfortunately, because if Javascript provided an object containing the name of the current script then it’d probably provide an object containing the current script’s path and this whole code would be redundant.

To use this reliably, ensure the script file has a unique name, such as <name-of-plugin>.init.js or similar. Then, within the file <name-of-plugin>.init.js, you can load the other resources using scriptPath()+'<resource>' such as scriptPath()+'/flash.swf' or scriptPath()+'/image.png'.

Because the above function scans the DOM every time it’s called, it’s sensible for performance reasons to store the result in a variable if it’s going to be called more than a couple of times.

Incidentally, script.aculo.us uses a variant of the above to load other resources but because their codebase depends on prototype they can write less code for this function. If your code depends on a library (jquery, mootools, prototype, etc…) then use what it provides; mine doesn’t, so I needed the above library independent method.

UPDATE March 2014: Thanks to Shawn who has been in touch to suggest an improvement to the above that allows for the query strings caching services typically add to the URLs such as ?v=3.8.1 or similar. In that case, the above will fail because the filename of the javascript file is expected to be the last component of the URL. To solve this problem you could use match(/\/script\.js($|\?.*$)/) and replace(/(.*)\/script\.js($|\?.*$)/, '$1') which makes the query string optional.