How can I reload an ES6 module at runtime?
Asked Answered
E

3

19

Prior to ES6 modules, it was (I'm told by other Stack answers) easy to force a JS script to be reloaded, by deleting its require cache:

delete require.cache[require.resolve('./mymodule.js')]

However, I can't find an equivalent for ES6 modules loaded via import.

That might be enough to make this question clear, but just in case, here's a simplified version of the code. What I have is a node server running something like:

-- look.mjs -- 
var look = function(user) { console.log(user + " looks arond.") }
export { look };

-- parser.mjs -- 
import { look } from './look.mjs';

function parse(user, str) {
    if (str == "look") return look(user);
}

What I want is to be able to manually change the look.mjs file (e.g. to fix a misspelled word), trigger a function that causes look.mjs to be reimported during runtime, such that parse() returns the new value without having to restart the node server.

I tried changing to dynamic import, like this:

-- parser.mjs -- 
function parse(user, str) {
    if (str == "look") {
        import('./look.mjs').then(m => m.look(user))
    }
}

This doesn't work either. (I mean, it does, but it doesn't reload look.mjs each time it's called, just on the first time) And I'd prefer to keep using static imports if possible.

Also, in case this is not clear, this is all server side. I'm not trying to pass a new module to the client, just get one node module to reload another node module.

Equator answered 22/4, 2020 at 22:21 Comment(1)
Node's import does not use the same require.cache. I'm going to take a guess that it leans heavily on v8 internals for the new import code so cache expiry might not be exposed.Turnbow
W
1

You could try using nodemon to dynamically refresh when you make code changes

https://www.npmjs.com/package/nodemon

Whiten answered 14/10, 2022 at 18:40 Comment(1)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewMonotheism
F
1

I agree with @tarek-salem that it's better to use vm library. But there is another way to solve your problem. There is no way to clear the dynamic import cache which you use in question (btw there is a way to clear the common import cache because require and common import has the same cache and the dynamic import has its own cache). But you can use require instead of dynamic import. To do it first create require in parser.mjs

import Module from "module";
const require = Module.createRequire(import.meta.url);  

Then you have 2 options:

  1. Easier: convert look.mjs into commonjs format (rename it look.cjs and use module.exports).

  2. If want to make it possible to either import AND require look.mjs you should create the npm package with package.json

     {
       "main": "./look.cjs", 
       "type": "commonjs" 
     }
    

In this case in parser.mjs you will be able to use require('look') and in other files import('look') or import * as look from 'look'.

Fresnel answered 19/12, 2022 at 12:10 Comment(0)
K
0

I don't know what the reason behind doing this, I think this is not safe to change the context of modules at runtime and cause unexpected behaviors and this is one of the reasons that Deno came to.

If you want to run some code evaluation at runtime you can use something like this using vm: https://nodejs.org/dist/latest-v16.x/docs/api/vm.html

Kildare answered 5/8, 2022 at 0:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.