【问题标题】:How do I wait to run the next npm command after the current command is complete?当前命令完成后如何等待运行下一个 npm 命令?
【发布时间】:2020-08-08 13:46:27
【问题描述】:

我知道,这听起来很简单。但请继续阅读以了解我面临的挑战。

我正在尝试创建一个“init”命令,以帮助设置克隆存储库以进行开发。我们使用远程包管理器,要求开发人员在处理包时在存储库中有一个.npmrc 文件(我们不想通过使用全局.npmrc 文件来限制用户)。这个过程应该是这样的:

  • 在终端提示用户输入用户名
  • .npmrc 文件写入他们的系统
  • 运行npm i
  • 运行npm run build

我在我的package.json 中创建了一个新的script

"init": "node ./scripts/writeNpmRc.js && npm i && npm run build && node ./scripts/init.js"

我的writeNpmRc.js 文件使用readline 获取用户输入,然后写入文件(请记住,此时我们还没有运行npm i,所以我们正在处理节点安装的内容)。

const readline = require('readline');
const fs = require('fs');
const path = require('path');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const writeFile = function(dest, data) {
  return new Promise((resolve, reject) => {
    fs.writeFile(dest, data, 'utf-8', function(err) {
      if (err) {
        reject(err);
      }
      resolve();
    });
  });
};

const getUsername = () => {
  const promise = new Promise((resolve, reject) => {
    try {
      rl.question(
        'What is your username (typically firstname.lastname)? ',
        result => {
          if (!result) {
            console.error('You must provide your username.');
            return getUsername();
          }
          resolve(result);
        }
      );
    } catch (err) {
      reject(err);
    }
  });
  return promise
    .catch(err => {
      console.error('[getUsername] ', err);
    })
    .finally(() => {
      rl.close();
    });
};

(async () => {
  const userName = await getUsername();

  const fileData = `registry=http://my.remote.repo/url/
email=${userName}@email.com`;

  await writeFile(path.resolve(__dirname, '../.npmrc'), fileData).catch(err => {
    console.err('[writeFile Error]', err);
  });

  console.log('[END writeNpmRcFile]');
  process.exit(0);
})();

这部分似乎运行良好,除了后续命令 (npm i) 没有使用新的 .npmrc 文件和安装炸弹。我可以(失败后)运行npm i 就好了,所以文件内容本身似乎是正确的。事实上,如果我手动放置一个.npmrc 文件并运行所有内容,除了writeNpmRcFile.js,它运行得很好。只有当我链接此命令时它们才会失败。

我知道我错过了什么,我只是不知道是什么?我等待fs.writeFile 成功完成(可能只使用writeFileSync...)。这就像文件系统没有及时释放.npmrc 文件以执行下一个命令。我什至设置了一个自定义 async wait() 方法,在某个时刻,该方法在退出进程之前暂停了一秒钟,但它没有帮助。有什么想法吗?

【问题讨论】:

  • AFAIK,(在简要浏览了source code 之后)npm 已经确定了配置应该是什么,然后在你的 npm 脚本中定义的命令被评估和执行。本质上,就 npm 而言,通过 npm 脚本生成的 .npmrc 文件根本不存在 - 它在运行脚本命令之前已经推断出配置设置。
  • 现在说得通了。我想知道(而不是在脚本行中链接我的命令)我是否可以使用child_process 来运行每个附加命令?或者,至少是npm i,因为这是唯一依赖.npmrc 的。作为一个子进程,它不会是一个单独的实例吗? (我想我只需要测试一下......)

标签: javascript node.js npm npm-scripts


【解决方案1】:

所以,@RobC 在他的评论中说得很有道理,在编写 .npmrc 文件之后,我测试了我关于使用 child_process 运行 npm i 步骤的后续理论。测试表明我认为正确,它在单独的上下文中运行命令,并且该上下文将使用新文件。对于那些好奇的人,这里是我更新的writeNpmRcFile.js,其中包括安装。

const readline = require('readline');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

let rl;
let spinnerInterval;

const getInterface = () =>
  readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

const writeFile = function(dest, data) {
  return new Promise((resolve, reject) => {
    fs.writeFile(dest, data, 'utf-8', function(err) {
      if (err) {
        reject(err);
      }
      resolve();
    });
  });
};

const runInstall = () => {
  console.log('Running npm install (This may take a few, so be patient)');
  spinnerInterval = twirlTimer();
  const promise = new Promise((resolve, reject) => {
    exec(
      'npm i',
      { cwd: path.resolve(__dirname, '../') },
      (err, stdout, stderr) => {
        clearInterval(spinnerInterval);
        if (err) {
          reject(err);
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
        resolve();
      }
    );
  });
  return promise.catch(err => {
    clearInterval(spinnerInterval));
    return Promise.reject(err);
  }
};

const twirlTimer = function() {
  var P = ['\\', '|', '/', '-'];
  var x = 0;
  return setInterval(function() {
    process.stdout.write('\r' + P[x++]);
    x &= 3;
  }, 250);
};

const getUsername = () => {
  if (!rl) rl = getInterface();
  const promise = new Promise((resolve, reject) => {
    try {
      rl.question(
        'What is your username (typically firstname.lastname)? ',
        result => {
          if (!result) {
            console.error('You must provide your username.');
            return getUsername();
          }
          resolve(result);
        }
      );
    } catch (err) {
      reject(err);
    }
  });
  return promise
    .catch(err => {
      console.error('[getUsername] ', err);
    })
    .finally(() => {
      rl.close();
    });
};

(async () => {
  const userName = await getUsername();

  // prettier-ignore
  const fileData = `registry=http://my.remote.repo/url/
email=${userName}@email.com`;

  console.log(`Writing your '.npmrc' file to the directory`);
  await writeFile(path.resolve(__dirname, '../.npmrc'), fileData).catch(err => {
    console.error('[writeFile Error] ', err);
  });

  await runInstall().catch(err => {
    console.log('[runInstall Error] ', err);
  });

  console.log('[END writeNpmRcFile]');
  process.exit(0);
})();

我的package.json scripts 对此进行了更改:

  "scripts": {
    "lint": "eslint ./scripts",
    "start": "node ./dist/index.js",
    "release": "standard-version",
    "write-npmrc": "node ./scripts/writeNpmRcFile.js",
    "init": "npm run write-npmrc && npm run build && node ./scripts/init.js",
    "build": "node ./scripts/build.js"
  }

【讨论】:

    猜你喜欢
    • 2018-04-03
    • 2023-03-06
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    相关资源
    最近更新 更多