Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#499·rubick

献计:完美内置npm方案,用户无需安装nodejs

Author: qiaolin-liCreated Jul 23, 2026Updated Jul 23, 2026
Labelsfeature

您的功能请求是否与问题相关? 请简单描述. npm安装插件问题

请描述一下您想要的解决方案 不需要用户安装 nodejs 即可下载插件

描述你考虑过的替代方案 以下内容引用我的一篇记录博客

参见: https://github.com/qiaolin-li/dubbo-desktop-manager/blob/master/docs/npm%E6%8F%92%E4%BB%B6%E5%AE%89%E8%A3%85%E5%99%A8.md

@muwoo 大佬,还记得几个月前我们的聊天吗? Image

现在我那个版本发布了,我带着解决方案来了。

既然npm6可用,那么npm8也应该是可以的,我查看 [email protected] 的源码。

npm 8 直接执行 require('npm') 会进入根 index.js,并抛出:

The programmatic API was removed in npm v8.0.0

但继续查看源码可以发现,npm CLI 仍然是运行在 Node.js 上的 JavaScript 程序,核心 Npm 类位于 lib/npm.js。

Electron 主进程就是 Node.js。因此我的最终方案是:把完整的 npm 8 打进应用,绕过根 index.js,直接加载 lib/npm.js,然后调用 load() 和 exec()。

项目固定 npm 版本并通过 Electron Builder 复制完整目录:

json
{
    "dependencies": {
        "npm": "8.19.4"
    },
    "build": {
        "extraResources": [
            "./node_modules/npm"
        ]
    }
}

NpmUtils 完整实现

NpmUtils 负责加载内置 npm、指定安装目录、选择镜像并转发安装日志:

javascript
// 开发和生产环境使用不同的 npm 路径:
const APPLICATION_NPM_PATH_PREFIX = IS_DEVELOPMENT
	? path.join(process.cwd(), 'node_modules/npm/')
    : path.join(process.resourcesPath, 'node_modules/npm/')

class NpmUtils {
    
    async execCommand (command, args, where){
        if (!command) {
            throw new Error('command is a must');
        }

        process.argv[0] = ''
        process.argv[1] = 'dist_electron'
        process.argv[2] = command
        for (let i = 0; i < args.length; i++) {
            process.argv.push(args[i]);
        }

        const Npm = require(`${APPLICATION_NPM_PATH_PREFIX}/lib/npm.js`)

        class MyNpm extends Npm {

            constructor (localPrefix) {
                super()
                this.localPrefix = localPrefix;
            }

			/** 安装依赖时会修改title,可能会影响应用的title,所以重写忽略 */
            set title (t) { }
        }

        const npm = new MyNpm(where)
        const stdoutWrite = process.stdout.write;
        const stderrWrite = process.stderr.write;

        try {
            process.stdout.write = (...msg) => {
                npm.output(...msg)
            }

            process.stderr.write = (...msg) => {
                npm.outputError(...msg)
            }
        
            await npm.load()

			// 可以设置更快的仓库
            npm.config.set('registry', 'https://registry.npmmirror.com/')
            const cmd = npm.argv.shift()
            await npm.exec(cmd, npm.argv)
        } finally {
            process.stdout.write = stdoutWrite;
            process.stderr.write = stderrWrite;
        }

        return npm.message;
    }    
}

export default new NpmUtils();

使用案例

安装插件:

javascript
await npmUtils.execCommand('install', ['[email protected]', '--loglevel', 'info'], pluginDirectory)

卸载插件:

javascript
await npmUtils.execCommand('uninstall', ['ddm-plugin-dubbo-support', '--loglevel', 'info'], pluginDirectory)

真实代码参见: PluginInstaller.js NpmUtils.js

(打个广告)我也是在用 Electron 做一个插件平台,本来是只做 Dubbo客户端的,慢慢的发现不满足了,就好玩做成了现在这个样子 仓库地址:https://github.com/qiaolin-li/dubbo-desktop-manager

ImageImage Image

Source: rubickCenter/rubick

View original on GitHubView discussion on GitHub