Принудительная перезагрузка при импорте асинхронных пакетов
В настоящее время я работаю над рефакторингом от большой унаследованной jQuery-кодовой базы к одностраничному приложению vue. При этом я надеюсь разделить свою работу на управляемые куски, сохраняя большую часть унаследованной кодовой базы как есть в коде, и медленно вытаскивая фрагменты и части из нее для рефакторинга в vue, используя шину событий как посредник.
Тем не менее, я сталкиваюсь с проблемами, потому что старый код имеет побочные эффекты при импорте. Эти побочные эффекты вызваны событием jquery времени выполнения, связанным с HTML, и создаваемыми объектами и экземплярами классов, оборачивающимися вокруг другого HTML, так как он устанавливает состояние сразу при импорте. Это вызывает проблему с рефакторингом SPA, так как я хочу иметь возможность перейти от страницы к странице, но javascript останется в кэше и не будет перезагружаться, теперь пропущены все обновления HTML и состояния, поскольку vue удалит html состояние было создано с добавлением нового html при повторном рендеринге.
Я ищу лучшее решение этой проблемы, чтобы мне не пришлось дважды проводить рефакторинг кода - сначала в модульный импорт с вызовами init, а затем в реактивную модульную парадигму vue. Для этого я хотел бы выяснить, как использовать асинхронный импорт фрагментов Webpack для перезагрузки блока кода. Я знаю, что это возможно из-за горячей перезагрузки файла. По сути, я хочу вызвать горячую перезагрузку определенного импорта при доступе к определенному маршруту.
Вот что я пытаюсь сделать:
async function reloadLegacyCodeOnSPARoutingChange(){
cleanAnyPolutingGlobals();
const initLegacyCode = await import(`./LegacyCode.js`); //somehow force it to reload this as if it were a fresh import
let thingId = this.$store.state.thingPage.thingId;
await initLegacyCode(thingId);
await EventBus.$emit('initLegacyCodeState'); //apply the properties from our reactive state system
}
Есть ли эффективный способ сделать это от клиента?
2 ответа
Вы можете динамически импортировать модуль и удалить его из кэша, если флаг useFresh
правда.
async function getFile (useFresh) {
try {
useFresh && delete require.cache[require.resolve('./Test')];
} catch (err) { }
let newModule = await require('./Test');
}
Примечание: если вы используете export default
в файле, который вы динамически импортируете, вам придется использовать newModule.default
чтобы получить доступ к его объектам.
Горячая замена модулей (HMR) - это не какая-то черная магия (хотя я так и думал). Представьте себе архитектуру клиент / сервер, в которой клиент (ваше приложение) запрашивает сервер (Webpack с включенной HMR), есть ли какие-либо изменения в модуле, который вы пытаетесь импортировать. Если это так, он перезагружает модуль.
// Add this to the file you are initially loading
if (module.hot) {
module.hot.accept('./LegacyCode.js', async function() {
console.log('Accepting the updated LegacyCode.js module!');
let thingId = this.$store.state.thingPage.thingId;
await initLegacyCode(thingId);
await EventBus.$emit('initLegacyCodeState');
})
}
На веб-сайте веб-пакета есть отличное руководство о том, как работает HMR и как начать работу.
ПРИМЕЧАНИЕ: AFAICT ваш старый код генерирует побочные эффекты при загрузке (например, он портит глобальное состояние). Я был бы очень осторожен с этим, поскольку горячая перезагрузка работает лучше всего, когда модули импортируются детерминистическим образом.