86

I'm trying to do something like a C #include "filename.c", or PHP include(dirname(__FILE__)."filename.php") but in javascript. I know I can do this if I can get the URL a js file was loaded from (e.g. the URL given in the src attribute of the tag). Is there any way for the javascript to know that?

Alternatively, is there any good way to load javascript dynamically from the same domain (without knowing the domain specifically)? For example, lets say we have two identical servers (QA and production) but they clearly have different URL domains. Is there a way to do something like include("myLib.js"); where myLib.js will load from the domain of the file loading it?

Sorry if thats worded a little confusingly.

Bart Verkoeijen
  • 16,545
  • 7
  • 52
  • 56
B T
  • 57,525
  • 34
  • 189
  • 207

12 Answers12

93

Within the script:

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

This works because the browser loads and executes scripts in order, so while your script is executing, the document it was included in is sure to have your script element as the last one on the page. This code of course must be 'global' to the script, so save src somewhere where you can use it later. Avoid leaking global variables by wrapping it in:

(function() { ... })();
Yves M.
  • 29,855
  • 23
  • 108
  • 144
InfinitiesLoop
  • 14,349
  • 3
  • 31
  • 34
  • 5
    This is a great suggestion, as long as the code in the script is run "inline" (i.e. in a global context or "immediate run anonymous method", as you've suggested, and not in a "called later" function or set-timeout). You could create a var in each javascript for the current file/path in this way. Careful however, "leaking global variables" cannot be solved by what I've called immediate-run-anon-methods, `(function(){...})();` - your example above will still create a global var called `src` because it does not have a `var` specifier before it – Graza Feb 12 '10 at 23:14
  • That is pretty brilliant. One problem is that if I use jquery's getScript method, it fails (returns blank). Any solution to that? – B T Feb 12 '10 at 23:24
  • 5
    There is a var specifier for 'src' (see comma on end of the first line) – InfinitiesLoop Feb 12 '10 at 23:30
  • @B T: don't use jQuery. :) Ooops, just kidding! – Marco Demaio Apr 14 '10 at 17:02
  • 1
    @InifinitesLoop: in a similar answer to a similar question they suggest to return scripts[scripts.length-1].getAttribute('src', -1), see more here: http://stackoverflow.com/questions/984510/what-is-my-script-src-url/984656#984656 – Marco Demaio Apr 14 '10 at 17:03
  • The issue of whether the url is resolved or not doesn't usually matter, since you'd probably want your code to work no matter how the 'src' attribute is specified. And whatever the value is, if you're using it in the same page context it came from, it will do the right thing. – InfinitiesLoop Apr 15 '10 at 18:43
  • @B T: beaware that InifinitesLoop code might return script src as a relative path on IE 6/7 (i.e. '/path/script.js') and the same script src as a full http path on IE8 / FF / Chrome / Safari (i.e. 'http://domain.com/path/script.js'). The code here is more cross-browser: http://stackoverflow.com/questions/984510/what-is-my-script-src-url/3865126#3865126 – Marco Demaio Oct 05 '10 at 15:35
  • This approach has served me well in many cases. Getting my own script path while inside of a Web Worker is not among them. – buley Mar 22 '14 at 20:06
  • 2
    @buley See my very recent answer below. Getting the file name from the stacktrace using the stackinfo module (github) might help you. – B T May 05 '14 at 00:35
  • The accepted answer here was not working for me because it was conflicting with inline scripts a document. To avoid this I wrote the function below to target – Kevinleary.net Sep 24 '14 at 17:44
  • 3
    This doesn't work if your ` – ComFreek Dec 02 '14 at 18:49
  • 1
    This won't work also if the script was added to the page with async and defer. – Carlos Ferreyra Jun 09 '17 at 13:58
67

All browsers except Internet Explorer (any version) have document.currentScript, which always works always (no matter how the file was included (async, bookmarklet etc)).

If you want to know the full URL of the JS file you're in right now:

var script = document.currentScript;
var fullUrl = script.src;

Tadaa.

Rudie
  • 52,220
  • 42
  • 131
  • 173
  • This is awesome and exactly what I was hoping to find! – Markus Jan 12 '16 at 16:38
  • Thanks, I finally find the solution ! – Alcalyn Apr 07 '16 at 17:41
  • 1
    I think it's good to know - if object is initialized outside from that file script, then that path is differet - so if someone want path of script it have to be called in root of that file script – Bruno Sep 10 '19 at 00:31
26

I just made this little trick :

window.getRunningScript = () => {
    return () => {      
        return new Error().stack.match(/([^ \n])*([a-z]*:\/\/\/?)*?[a-z0-9\/\\]*\.js/ig)[0]
    }
}
console.log('%c Currently running script:', 'color: blue', getRunningScript()())

screenshot

Works on: Chrome, Firefox, Edge, Opera

Enjoy !

Alexandre Daubricourt
  • 3,323
  • 1
  • 34
  • 33
  • 1
    This is great! I was having an issue because my javascript file is being inserted via a chrome extension and not through conventional means. Looking at `document.currentScript.src` and looking at the previously added ` – evan Nov 27 '22 at 13:41
  • Also, I've I've never seen that color trick in `console.log` before. Very cool. – evan Nov 27 '22 at 13:42
18

The accepted answer here does not work if you have inline scripts in your document. To avoid this you can use the following to only target <script> tags with a [src] attribute.

/**
 * Current Script Path
 *
 * Get the dir path to the currently executing script file
 * which is always the last one in the scripts array with
 * an [src] attr
 */
var currentScriptPath = function () {

    var scripts = document.querySelectorAll( 'script[src]' );
    var currentScript = scripts[ scripts.length - 1 ].src;
    var currentScriptChunks = currentScript.split( '/' );
    var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];

    return currentScript.replace( currentScriptFile, '' );
}

This effectively captures the last external .js file, solving some issues I encountered with inline JS templates.

Kevinleary.net
  • 8,851
  • 3
  • 54
  • 46
9

Refining upon the answers found here I came up with the following:

getCurrentScript.js

var getCurrentScript = function() {
  if (document.currentScript) {
    return document.currentScript.src;
  } else {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1].src;
  }
}

// module.exports = getCurrentScript;
console.log({log: getCurrentScript()})

getCurrentScriptPath.js

var getCurrentScript = require('./getCurrentScript');

var getCurrentScriptPath = function () {
  var script = getCurrentScript();
  var path = script.substring(0, script.lastIndexOf('/'));
  return path;
};

module.exports = getCurrentScriptPath;

BTW: I'm using CommonJS module format and bundling with webpack.

Teocci
  • 7,189
  • 1
  • 50
  • 48
Stoutie
  • 1,944
  • 1
  • 21
  • 17
5

I've more recently found a much cleaner approach to this, which can be executed at any time, rather than being forced to do it synchronously when the script loads.

Use stackinfo to get a stacktrace at a current location, and grab the info.file name off the top of the stack.

info = stackinfo()
console.log('This is the url of the script '+info[0].file)
B T
  • 57,525
  • 34
  • 189
  • 207
3

I've coded a simple function which allows to get the absolute location of the current javascript file, by using a try/catch method.

// Get script file location
// doesn't work for older browsers

var getScriptLocation = function() {
    var fileName    = "fileName";
    var stack       = "stack";
    var stackTrace  = "stacktrace";
    var loc     = null;

    var matcher = function(stack, matchedLoc) { return loc = matchedLoc; };

    try { 

        // Invalid code
        0();

    }  catch (ex) {

        if(fileName in ex) { // Firefox
            loc = ex[fileName];
        } else if(stackTrace in ex) { // Opera
            ex[stackTrace].replace(/called from line \d+, column \d+ in (.*):/gm, matcher);
        } else if(stack in ex) { // WebKit, Blink and IE10
            ex[stack].replace(/at.*?\(?(\S+):\d+:\d+\)?$/g, matcher);
        }

        return loc;
    }

};

You can see it here.

William
  • 8,007
  • 5
  • 39
  • 43
Afonso Matos
  • 2,406
  • 1
  • 20
  • 30
3

Refining upon the answers found here:

little trick

getCurrentScript and getCurrentScriptPath

I came up with the following:

//Thanks to https://stackoverflow.com/a/27369985/5175935
var getCurrentScript = function() {

  if (document.currentScript && (document.currentScript.src !== ''))
    return document.currentScript.src;
  var scripts = document.getElementsByTagName('script'),
    str = scripts[scripts.length - 1].src;
  if (str !== '')
    return str ;
  //Thanks to https://stackoverflow.com/a/42594856/5175935
  return new Error().stack.match(/(https?:[^:]*)/)[0];

};

//Thanks to https://stackoverflow.com/a/27369985/5175935
var getCurrentScriptPath = function() {
  var script = getCurrentScript(),
    path = script.substring(0, script.lastIndexOf('/'));
  return path;
};

console.log({path: getCurrentScriptPath()})
Teocci
  • 7,189
  • 1
  • 50
  • 48
Andrej
  • 679
  • 5
  • 14
1

I may be misunderstanding your question but it seems you should just be able to use a relative path as long as the production and development servers use the same path structure.

<script language="javascript" src="js/myLib.js" />
johnmdonahue
  • 653
  • 7
  • 16
  • 2
    The problem is that this javascript library is meant to be loaded on different domains. – B T Feb 12 '10 at 23:12
  • So is this a single js library file located on one domain that needs to be pulled in across multiple domains? Or is this a js file that resides on multiple domains that need to pull in other js files relative to its source? Could you provide an example of what you are trying to accomplish? – johnmdonahue Feb 12 '10 at 23:17
  • Its both actually. The js file will reside on multiple domains (QA vs production), and it will also be included from multiple domains (whatever web app needs to use the library). – B T Feb 12 '10 at 23:26
  • This may be what you're trying to get around, but could you hardcode the path of the script as a variable and have devel and production versions of your lib that have that line being their only difference? Or more simply pass something to a single script as a get param that specifies its location: ?devel=true – johnmdonahue Feb 12 '10 at 23:47
  • That is what I'm trying to avoid. I'm also trying to avoid a GET parameter, but thats a perfectly valid solution. I'm just too lazy to much around in all our Java Struts stuff for this. : ) – B T Feb 13 '10 at 01:18
1

Regardless of whether its a script, a html file (for a frame, for example), css file, image, whatever, if you dont specify a server/domain the path of the html doc will be the default, so you could do, for example,

<script type=text/javascript src='/dir/jsfile.js'></script>

or

<script type=text/javascript src='../../scripts/jsfile.js'></script>

If you don't provide the server/domain, the path will be relative to either the path of the page or script of the main document's path

Graza
  • 5,010
  • 6
  • 32
  • 37
1

I've thrown together some spaghetti code that will get the current .js file ran (ex. if you run a script with "node ." you can use this to get the directory of the script that's running)

this gets it as "file://path/to/directoryWhere/fileExists"

var thisFilesDirectoryPath = stackinfo()[0].traceline.substring("readFile (".length, stackinfo()[0].traceline.length - ")".length-"readFile (".length);

this requires an npm package (im sure its on other platforms as well):

npm i stackinfo

import stackinfo from 'stackinfo'; or var {stackinfo} = require("stackinfo");

  • With node you can just use `__dirname`. My question was really about browser js. – B T May 24 '22 at 15:50
  • @BT not always - i made this because for some reason __dirname didn't exist in my project. – GavinGoGaming May 27 '22 at 00:56
  • You might have been using es6 modules, which for some reason gets rid of it. This brings it back: ``` const __filename = url.fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); ``` – B T May 28 '22 at 17:48
0
function getCurrnetScriptName() {
    const url = new URL(document.currentScript.src);
    const {length:len, [len-1]:last} = url.pathname.split('/');
    return last.slice(0,-3);
}
Slev7n
  • 343
  • 3
  • 14