Импорт модуля перехвата JavaScript
У меня есть SPA (в Aurelia/ TypeScript но это не имеет значения), который использует SystemJS. Пусть говорят, что оно работает при http://spa:5000/app
.
Иногда он загружает модули JavaScript, такие как waterservice/external.js
по запросу с внешнего URL, например http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js
. Я использую SystemJS.import(url)
для этого, и он отлично работает.
Но когда этот внешний модуль хочет импортировать другой модуль с простым import { OtherClass } from './other-class';
, это (по понятным причинам) не работает. При загрузке SPA он выглядит http://spa:5000/app/other-class.js
. В этом случае мне нужно перехватить путь/местоположение, чтобы перенаправить его на http://otherhost:5002/fetchmodule?moduleId=other-class.js
.
Примечание. Компиляция TypeScript для waterservice/external.ts
работает, потому что компилятор TypeScript может легко найти ./other-class.ts
. Очевидно, я не могу использовать абсолютный URL для импорта.
Как перехватить загрузку модуля внутри модуля, который я импортирую с помощью SystemJS?
Один из подходов, который я уже тестировал, - это добавить отображение в конфигурацию SystemJS. Если я импортирую его как import { OtherClass } from 'other-class';
и добавлю отображение типа "other-class": "http://otherhost:5002/fetchmodule?moduleId=other-class"
, он будет работать. Но если этот подход хорош, как я могу добавить динамическое отображение во время выполнения?
Другие подходы, такие как общий перехват URL-адреса, также приветствуются.
Обновление
Я попытался перехватить SystemJS как предложение artem как это
var systemLoader = SystemJS;
var defaultNormalize = systemLoader.normalize;
systemLoader.normalize = function(name, parentName) {
console.error("Intercepting", name, parentName);
return defaultNormalize(name, parentName);
}
Как правило, это ничего не меняет, а выводит какой-то консольный вывод, чтобы увидеть, что происходит. К сожалению, это, похоже, что-то меняет, потому что я получаю сообщение об ошибке. Непонятно (в обещании) TypeError: this.has не является функцией внутри system.js
.
Затем я попытался добавить сопоставления с SystemJS.config({map: ...});
. Удивительно, но эта функция работает инкрементно, поэтому, когда я ее называю, она не освобождает уже предоставленные сопоставления. Поэтому я могу сделать:
System.config({map: {
"other-class": `http://otherhost:5002/fetchModule?moduleId=other-class.js`
}});
Это не работает с относительными путями (те, которые начинаются с .
или ..
), но если я поместил общие в корневой каталог , это будет работать.
Я бы предпочел перехватить загрузку, чтобы иметь возможность обрабатывать больше сценариев, но на данный момент я понятия не имею, какая функция has
отсутствует в приведенном выше подходе.
Ответы
Ответ 1
как я могу динамически добавлять отображение во время выполнения?
AFAIK SystemJS можно настроить в любое время, просто позвонив
SystemJS.config({ map: { additional-mappings-here ... }});
Если это не сработает для вас, вы можете переопределить loader.normalize и добавить свое собственное сопоставление от идентификаторов модулей к URL-адресам. Что-то в этом роде:
// assuming you have one global SystemJS instance
var loader = SystemJS;
var defaultNormalize = loader.normalize;
loader.normalize = function(name, parentName) {
if (parentName == 'your-external-module' && name == 'your-external-submodule') {
return Promise.resolve('your-submodule-url');
} else {
return defaultNormalize.call(loader, name, parentName);
}
}
Я не знаю, будет ли это работать с typescript или нет. Кроме того, вам нужно будет выяснить, какие имена точно передаются loader.normalize в вашем случае.
Кроме того, если вы используете компоновщик systemjs для связывания кода, вам нужно будет добавить это переопределение к загрузчику, используемому построителем (и всему этому другому рассказу).