Принудительная перезагрузка при импорте асинхронных пакетов

В настоящее время я работаю над рефакторингом от большой унаследованной 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 ваш старый код генерирует побочные эффекты при загрузке (например, он портит глобальное состояние). Я был бы очень осторожен с этим, поскольку горячая перезагрузка работает лучше всего, когда модули импортируются детерминистическим образом.

Другие вопросы по тегам