John Kulp
John Kulp

Reputation: 123

Force Reload on Webpack Async Import

I'm currently working on a refactor from a large legacy jquery-only codebase to a vue single page application. In doing so, I'm hoping to separate out my work into managable chunks, maintaining much of the legacy codebase as-is in the code, and slowly pulling pieces and parts out of it to refactor to vue, using an event bus as an intermediary.

However, I'm running into issues because the legacy code has side effects when imported. These side effects are caused by runtime jquery event bound to HTML, and objects and class instances being created wrapping around other HTML as it establishes state immediately on import. This causes a problem with the SPA refactor since I want to be able to navigate away from the page then back to it, but the javascript will remain cached and not reload, now missing all of the HTML and state updates since vue will have removed the html the state was created with then add new html on the re-render.

I'm looking for the best solution to this issue to keep me from having to refactor the code twice--once into a modular import with init calls, and then into a reactive, modular vue paradigm. To do that, I'd like to figure out how to use Webpack's async chunk imports to reload the block of code. I know this is possible due to webpack's hot reloading on a file. I essentially want to force a hot reload of certain imports when a certain route is accessed.

This is what I'm trying to do:

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
}

Is there an effective way to do this from the client?

Upvotes: 2

Views: 2266

Answers (2)

varun agarwal
varun agarwal

Reputation: 1509

You could dynamically import the module and delete it from the cache if the flag useFresh is true.

async function getFile (useFresh) {
    try {
        useFresh && delete require.cache[require.resolve('./Test')];
    } catch (err) { }
    let newModule = await require('./Test');
}

Note: If you're using export default in the file that you are dynamically importing, then you will have to use newModule.default to access its objects.

Upvotes: 1

Kostas Pelelis
Kostas Pelelis

Reputation: 1342

Hot module replacement(HMR) is not some sort of black magic (although I thought it was). Imagine a client/server architecture where the client (your application) asks the server (Webpack with HMR enabled) if there are any changes in the module you are trying to import. If so, it reloads the module.

// 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');
  })
} 

There is a great guide on the webpack website on how HMR works and how to get started

NOTE: AFAICT your legacy code generates side effects when it is loaded (e.g. it messes up the global state). I would be extra careful with that as hot reloading works best when modules are imported in a deterministic manner.

Upvotes: 0

Related Questions