2

I have a CGI application that had been working correctly for a long time, but recently broke, apparently because of a change in rules for where js scripts get loaded from. I'm using the solution from this answer to load js code conditionally from an external source. My version of the code looks like this:

function load_external_js(s) {
  // usage: load_external_js({src:"http://foo.com/bar.js",
  //                        element:"head",type:"text/javascript"});
  // ... defaults (the values shown above) are provided for element and type
  // http://stackoverflow.com/a/15521523/1142217
  // src can be a url or a filename
  var js = document.createElement("script");
  js.src = s.src;
  js.type = (typeof s.type === 'undefined') ? 'text/javascript' : s.type;
  var element = (typeof s.element === 'undefined') ? 'head' : s.element;
  var e = document.getElementsByTagName(element)[0];
  e.appendChild(js);
    // BUG -- no error handling if src doesn't exist
}

The issue I'm running into seems to be related to how either the browser or the server resolves relative file paths in this context. What I was doing was this:

load_external_js({src:"foo.js"});

This used to load foo.js from the same directory where the calling js script lived, which was something like /var/www/html/js/3.0.4. But recently this behavior has changed, and the file is searched for in the directory /usr/lib/cgi-bin/myapp, presumably because the html is generated by a CGI script. I can hardcode the directory like this:

load_external_js({src:"/js/3.0.4/mathjax_config.js"});

But this is ugly, and I would have to have some mechanism for setting the version number. Is there some way in pure js to do this so that the script is loaded from the same directory as the one in which the calling script lives? Googling has turned up lots of answers involving node.js or jquery, but I'm not using those.

2 Answers2

1

It's difficult to test this without replicating the setup you're working with, but in my experience this should work well:

var load_external_js = (function () {
  var base = document.currentScript.src;
  var a = document.createElement('a');
  a.href = base.split('/').slice(0, -1).join('/') + '/';

  var resolve = function (src) {
    var a = this.cloneNode();
    a.href += src;
    return a.href;
  }.bind(a);

  return function (s) {
    // usage: load_external_js({src:'http://foo.com/bar.js',
    //                        element:'head',type:'text/javascript'});
    // ... defaults (the values shown above) are provided for element and type
    // http://stackoverflow.com/a/15521523/1142217
    // src can be a url or a filename
    var js = document.createElement('script');
    js.src = resolve(s.src); // relative to <script> this is closure is in
    js.type = (typeof s.type === 'undefined') ? 'text/javascript' : s.type;
    var element = (typeof s.element === 'undefined') ? 'head' : s.element;
    var e = document.getElementsByTagName(element)[0];
    e.appendChild(js);
  };
})();
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
0

If you have access to html markup too, try to use <base> element or simply use document.baseURI and construct full path yourself.

Vasily Liaskovsky
  • 2,248
  • 1
  • 17
  • 32
  • 1
    I don't think this helps. In my situaiton, document.baseURI gives http://example.com/cgi-bin/myapp/myapp.cgi, which is the directory I don't want. –  Jan 03 '18 at 01:59