在 Typescript 中更新导入的模块

Posted

技术标签:

【中文标题】在 Typescript 中更新导入的模块【英文标题】:Update an imported module in Typescript 【发布时间】:2021-08-07 03:21:05 【问题描述】:

对不起,我对这门语言有点陌生。 这些天我正在创建一个自定义的不和谐机器人,但我被困在了这个问题上...... 我让这个机器人可以从一个文件夹中动态加载命令,每个命令都有一个模块,但现在我试图创建一个命令来重新加载它们,但每次重新加载命令后,输出总是相同的。

代码如下:

refreshCommands = () => 
    this.commands = ;
    console.log("Refreshing commands");
    Promise.all(fs.readdirSync("./dist/commands").map(file => 
        return new Promise(async resolve => 
            const tmp = (await import(`./commands/$file`)).default;
            this.commands[tmp.name] = tmp;
            resolve(tmp);
        );
    )).then(() => 
        console.log("Listing commands: ");
        console.log(Object.keys(this.commands));
    );

当然,我从 js 文件更新命令,而不是从 ts 更新命令,因为我必须再次编译它。 我试着做一个简单的“ping!Pong!” like 命令,然后将其编辑为“ping!ping!”在使用 //reload 命令之前在运行时,但它一直在写“ping!Pong!”

编辑 1: 我必须导入的模块是这样的:

import command from "../utils/command";
import  Guild, GuildEmoji, GuildEmojiManager, Message, MessageEmbed, Role  from "discord.js";
import  games  from "../utils/games";
import app from "../app";
import ReactionListener from "../utils/reactionListener";

const roleMessage: command = 
    name: "rolesMessage",
    description: "",
    execute: async (message, bot) => 
        message.delete();
        createRoles(message.guild as Guild);
        const embed = new MessageEmbed()
            .setColor('#F00')
            .setTitle("React to set your ROLE!");
    
        games.forEach(game => 
            let emoji = message.guild?.emojis.cache.find(emoji => emoji.name === game.emoji);
            console.log(emoji);
            embed.fields.push(
                name: game.name,
                value: (emoji as GuildEmoji).toString(),
                inline: false
            );
        );

        const msg = await message.channel.send(embed);
        app.reactionListeners.push(new ReactionListener(msg, 
            (reaction, user) => 
                let tmp = games.find(game=> reaction.emoji.name === game.emoji);
                if(tmp)
                    //msg.channel.send(tmp);
                    const role = (message.guild as Guild).roles.cache.find(role => role.name === tmp?.roleName) as Role;
                    message.guild?.members.cache.find(member => member.id === user.id)?.roles.add(role);
                else
                    reaction.remove();
                
            , (reaction, user)=>
                let tmp = games.find(game=> reaction.emoji.name === game.emoji);
                if(tmp)
                    //msg.channel.send(tmp);
                    const role = (message.guild as Guild).roles.cache.find(role => role.name === tmp?.roleName) as Role;
                    message.guild?.members.cache.find(member => member.id === user.id)?.roles.remove(role);
                
            )
        );

        games.forEach(game => 
            msg.react((message.guild?.emojis.cache.find(emoji => emoji.name === game.emoji) as GuildEmoji));
        );
    


const createRoles = (guild: Guild) => 
    games.forEach(game => 
        if(!guild.roles.cache.find(role => role.name === game.roleName))
            guild.roles.create(
                data: 
                name: game.roleName,
                color: "#9B59B6",
            ,
                reason: 'we needed a role for Super Cool People',
            )
            .then(console.log)
            .catch(console.error);
        
    );


export default roleMessage;

这和我之前说的不一样,但问题是一样的...一旦我更新并重新加载它(从js编译版本),旧版本一直在运行

【问题讨论】:

导入结果被缓存,因此再次导入不会加载较新的内容。根据文件中的内容,您可以自己读取文件,然后在其上运行eval() 您将如何编辑我的代码以使其运行? 正如我所说,您必须显示您正在导入的这些文件中的内容。我的感觉是,有比您尝试的更好的方法来做到这一点,但我必须查看实际文件才能知道要建议什么。 我刚刚用我正在导入的代码更新了它...有什么想法吗? 嗯,这不是 nodejs 擅长的(用更新的代码动态替换现有代码)。它积极地试图阻止你这样做。我唯一能想到的就是将新文件放在不同的目录中(您在本次会议中从未使用过的目录)并从那里导入它们。这将使import 系统认为它们是新文件。但它会“泄漏”内存,因为旧版本的代码永远不会被垃圾回收。 【参考方案1】:

我设法找到了解决问题的方法。 由于节点 js 会在导入后对每个模块进行缓存,因此我像这样从缓存中删除了它

refreshCommands = () => 
    Promise.all(fs.readdirSync("./dist/commands").map(file => 
        return new Promise(async resolve => 
            delete require.cache[require.resolve('./commands/' + file)];
            resolve(file);
        );
    )).then(() => 
        this.commands = ;
        console.log("Refreshing commands");
        Promise.all(fs.readdirSync("./dist/commands").map(file => 
            return new Promise(async resolve => 
                const tmp = (await import(`./commands/$file`)).default;
                this.commands[tmp.name] = tmp;
                resolve(tmp);
            );
        )).then(() => 
            console.log("Listing commands: ");
            console.log(Object.keys(this.commands));

        );
    );

代码可能看起来像垃圾,但它确实有效......我正在努力让它变得更好,但同时我可以依赖它。 任何建议都可以接受

【讨论】:

以上是关于在 Typescript 中更新导入的模块的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Typescript、React 和 Webpack 导入 SCSS 或 CSS 模块

如何从节点模块中的@types 保存类型

如何为所有节点模块自动安装@types

三eggjs学习记录 - typescript声明放到types里面

在 TypeScript 中找不到模块的声明文件

如何让 TypeScript 以生成工作 Node.JS 代码的方式加载 PDF.js NPM 模块和 @types 绑定?