2

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?

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

That sounds promising! I've tried messing with the require.resolve cache before, but I'll give it another go using await require rather than the webpack async import function, though I don't know if they're just the same functionality with different syntax
They're more or less the same with different syntax. webpack.js.org/api/module-methods/#commonjs
I feel like this approach should work, but we've been slaving away at it, and it just doesn't seem to get it to reload even though it feels like it should. Thanks for the help though!
0

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.

5 Comments

The problem here is that webpack doesn't seem to have any documentation on how to say that a module has changed even when it hasn't. I've looked through the documentation there, but I didn't find a way to actually request a new copy from the server. Am I just missing something straightforward with it?
With the side effects, I've already accounted for resetting the global state. The reason this hot reloading is important is to essentially quick-fix modularizie those side effects to restart at the correct time.
The dev server (in theory) is watching your files for changes, so it should detect when the module has changed. Can you provide your webpack config?
That is again, not what I'm trying to do. I don't want to reload the file when the module changes. I want to reload the file in order to re-run the javascript side-effects without a major refactor. I want to do this when the client goes to a certain route, every time they do so. Not when something happens on the server. I want hot reloading, but for production use in re-loading scripts to run again, not for reacting to changed files on the server.
I think I may be having a similar issue. my jquery code only executes once with hot reloading after I comment out if (module.hot) { module.hot.accept()}, after that it wont reload it again. Would anyone know why this is happening? do I need to modify the hot reload function somehow?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.