CNode

如何能够引入刚下载的第三方模块?

问答
Llinzb93发布于5 年前最后回复5 年前7 回复5517 浏览0 收藏

我想实现一个函数,当目标模块已下载时,直接通过 require 引入,否则去npm下载,完成后再引入。 原先的代码是这样的:

const execa = require('execa');
const requireDynamic = async moduleName => {
    try {
        return require(moduleName);
    } catch {
        await execa('npm', ['install', moduleName]);
        return require(moduleName);
    }
};

但是这样会报错,提示模块不存在。 而我在模块安装结束后用下面这段代码确认模块已经安装,模块文件夹是存在的:

const fs = require('fs-extra');
const path = require('path');
console.log(fs.pathExists(path.resolve(process.cwd(), 'node_modules', moduleName)));

我怀疑模块下载成功后没能立即允许引入,所以开了定时器setInterval 来确认什么时候可以引入,但是一直都不可以。 后来我先找到这个模块的package.json ,然后在main字段找到模块的入口文件,引入这个文件,是可以的。

const execa = require('execa');
const path = require('path');
const requireDynamic = async moduleName => {
    try {
        return require(moduleName);
    } catch {
        await execa('npm', ['install', moduleName]);
        const modulePath = path.resolve(process.cwd(), 'node_modules', moduleName);
        const { main } = require(path.resolve(modulePath, 'package.json'));
        return require(path.resolve(modulePath, main));
    }
};

我就是没明白,npm模块从下载,解压,还要经过什么流程,才可以被正常引入。希望有好心人解答下,谢谢了。

查看回复

回复 (7)

D
dbit-xia#1·5 年前

webstorm里可以看到require实现的源码 楼主可以试试看

L
linzb93#2·5 年前
引用 xiaoxiaojx@linzb93 打扰了

@xiaoxiaojx 我找到解决方案了。 delete require.cache[] 数组里面填写的不能是moduleName,因为之前require失败,缓存里面找不到moduleName对应的地址。 应该改成path.resolve(process.cwd(), 'node_modules', moduleName)就可以成功删除了。

Z
zurmokeeper#3·5 年前

其实没必要这样操作,如果你的目的只是不想多下载一次,可以使用pnpm,每个版本的包只会下载一次。写成这样,如果原理了解不够透彻或者测试不够充分,容易留下隐患

X
xiaoxiaojx#4·5 年前

目测 require 缓存造成的,catch 语句里面先删除一次缓存试试

await execa('npm', ['install', moduleName]);
delete require.cache[moduleName];
return require(moduleName);
L
linzb93#5·5 年前
参与回复
登录后即可参与回复。登录