NodeJS 如何在运行时重新加载ES6模块?

b1uwtaje  于 2022-12-22  发布在  Node.js
关注(0)|答案(3)|浏览(135)

在ES6模块之前,通过删除其require缓存,强制重新加载JS脚本是很容易的(我从其他Stack答案中得知):

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

但是,我找不到通过import加载的ES6模块的等效模块。
这可能已经足够让这个问题清楚了,但为了以防万一,这里有一个代码的简化版本,我有一个节点服务器,运行如下代码:

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

我想要的是能够手动更改look.mjs文件(例如,修复拼写错误的单词),触发一个函数,使look.mjs在运行时重新导入,这样parse()就可以返回新值,而不必重新启动节点服务器。
我尝试更改为动态导入,如下所示:

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

这也不起作用。(我的意思是,它起作用了,但是它不会在每次调用时重新加载look.mjs,只是在第一次调用时)如果可能的话,我更喜欢继续使用静态导入。
另外,如果这一点不清楚,这是所有的服务器端。我不试图传递一个新的模块到客户端,只是让一个节点模块重新加载另一个节点模块。

wlzqhblo

wlzqhblo1#

我不知道这样做背后的原因是什么,我认为在运行时更改模块的上下文并导致意外行为是不安全的,这也是Deno选择这样做的原因之一。
如果你想在运行时运行一些代码评估,你可以使用vm来执行类似这样的操作:https://nodejs.org/dist/latest-v16.x/docs/api/vm.html

fnvucqvd

fnvucqvd2#

您可以尝试在更改代码时使用nodemon动态刷新
https://www.npmjs.com/package/nodemon

xn1cxnb4

xn1cxnb43#

我同意@tarek-salem的观点,最好使用vm库。但是有另一种方法可以解决你的问题。没有办法清除你使用的动态导入缓存(顺便说一下,有一种方法可以清除公共导入缓存,因为require和公共import具有相同的缓存,而动态import具有自己的缓存)。但是可以使用require代替动态导入。要执行此操作,请首先在parser.mjs中创建require

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

那么你有两个选择:
1.更简单:将look.mjs转换为commonjs格式(重命名为look.cjs并使用module.exports)。
1.如果希望能够使用importrequire查找.mjs,则应使用package.json创建npm包

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

在这种情况下,在parser.mjs中,您将能够使用require('look'),在其他文件中,您将能够使用import('look')import * as look from 'look'

相关问题