У меня есть CGI-приложение, которое долгое время работало правильно, но недавно сломалось, по-видимому, из-за изменения правил, откуда загружаются js-скрипты. Я использую решение из этого ответа для условной загрузки js-кода из внешнего источника. Моя версия кода выглядит так:

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
}

Проблема, с которой я сталкиваюсь, похоже, связана с тем, как браузер или сервер разрешают относительные пути к файлам в этом контексте. Я делал вот что:

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

Это использовалось для загрузки foo.js из того же каталога, в котором находился вызывающий js-скрипт, который был чем-то вроде /var/www/html/js/3.0.4. Но недавно это поведение изменилось, и файл ищется в каталоге /usr/lib/cgi-bin/myapp, предположительно потому, что html генерируется сценарием CGI. Я могу жестко закодировать каталог следующим образом:

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

Но это некрасиво, и мне нужен какой-то механизм для установки номера версии. Есть ли способ в чистом js сделать это так, чтобы скрипт загружался из того же каталога, что и тот, в котором живет вызывающий скрипт? Поиск в Google дал много ответов, связанных с node.js или jquery, но я их не использую.

2
Ben Crowell 3 Янв 2018 в 04:13

2 ответа

Лучший ответ

Трудно проверить это, не копируя настройку, с которой вы работаете, но, по моему опыту, это должно работать хорошо:

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);
  };
})();
2
Patrick Roberts 3 Янв 2018 в 14:56

Если у вас также есть доступ к разметке html, попробуйте использовать <base> или просто используйте document.baseURI и создайте полный путь самостоятельно.

0
Vasily Liaskovsky 3 Янв 2018 в 01:20