npm-proxy-login使用

299 阅读2分钟

背景:我们在发布 npm package 的时候,需要注册私有的 registry,使用 npm adduser, 在这个过程中我们会和 npm 进行交互式连接,npm-proxy-login 就是帮助我们使用 nodejs 进行交互式输入 账号、密码、邮箱, 在此过程中无需手动输入任何信息,nodejs脚本实现一键登录

  1. 正常情况下发布一个npm包,需要对发布的 registry 进行 adduser, 会触发 npm 的 交互式命令行 (需要手动 一行一行的 输入 usernamepasswordemail, 比较麻烦, 而且在 CI Runner 也没办法进行一行一行的输入,此时就需要一个脚本完成一次新输入)

    1. 见下图,当我们执行 npm adduser 的时候需要我们输入 username,当 username 输入完成
    2. 按下回车,需要输入 password, 当 password 输入完成
    3. 按下回车,需要输入 email
    4. 通过上述usernamepasswordemail 输入完成,才可以 login 成功

image.png

  1. 使用 npm-proxy-login 实现一行脚本自动 login
// package.json
{
  "initPrivateRegistry": "npx npm-proxy-login https://priveta-registry username password email"
}

3. 通过 npx 调用 该脚本,需要传入4个参数,分别代表 (私有的 npm 源、 账号、密码、邮箱)

  1. 如果在 CI Runner里面使用,一般情况下,usernamepasswordemail 都会设置为 Mask,可以直接在 gitlab_ci.yaml 中调用此脚本,可以正常实现 registry login

  2. 实现原理

    1. 拿到传入的4个参数,调用 exec 进行 执行 子进程的 shell 命令

    2. 在执行过程中设置 stdio 为[0, 1, 2]。

      1. 0:表示子进程的 stdin 继承自父进程的 stdin
      2. 1: 表示继承子进程的 stdout
      3. 2: 继承自父进程的 stderr
    3. 拿到 nodejs 给的 stdout,切割准备好的参数进入填入 stdout 的输入

  3. 源码地址

#!/usr/bin/env node
const { exec } = require("child_process");

const [registry, ...otherArgvList] = process.argv.slice(2);

const inputArray = otherArgvList.reduce((result, item) => {
        result.push(item + "\n");
        return result;
}, []);

const result = exec(
        `npm adduser --registry ${registry}`,
        {
                shell: true,
                async: true,
                stdio: [0, 1, 2],
                timeout: 600000,
        },
        (err, stdout) => {
                console.log(err, "err", stdout, "stdout");
                if (err) {
                        process.exit(1);
                }
        },
);
result.stdout.on("data", (chunk) => {
        console.log(chunk, "接收到的输入: -> ", chunk.toString());
        if (chunk.toString()?.trim?.()) {
                const cmd = inputArray.shift();
                result.stdin.write(String(cmd));
        }
});

process.on("error", () => {
        process.exit(1);
});