【问题标题】:Run another yarn/npm task within a package.json, without specifying yarn or npm在 package.json 中运行另一个 yarn/npm 任务,无需指定 yarn 或 npm
【发布时间】:2020-06-13 02:37:45
【问题描述】:

我的 package.json “deploy”中有一个任务,需要先调用“build”。我是这样指定的:

"deploy": "yarn run build;./deploy.sh",

问题是这个硬编码yarn 为包管理器。所以如果有人不使用yarn,它就不起作用。切换到 npm 会导致类似的问题。

在不知道npmyarn 的选择的情况下,有什么好的方法可以实现这一目标?

【问题讨论】:

  • Rico 的回答让我想到了一些事情。对硬编码“工具”存在担忧,如果使用 Windows 的人想要运行它怎么办? .sh 行不通……我想值得深思……
  • 是的,但这属于必须做大量额外工作才能支持第二个平台的范畴。

标签: node.js npm yarnpkg package.json


【解决方案1】:

一种简单的方法是使用npm-run-all 包,其文档指出:

纱线兼容性

如果使用 Yarn 调用脚本,npm-run-all 将正确使用 Yarn 执行计划的子脚本。

所以你可以这样做:

"predeploy": "run-s build",
"deploy": "./deploy.sh",

predeploy 步骤将使用 npm 或 yarn,具体取决于您调用 deploy 任务的方式。

我认为最好让 package.json 中的运行保持与包管理器无关,这样它们就不会绑定到特定的包管理器,但在项目中,同意使用单个包管理器可能是谨慎的包管理器,这样您就不会处理冲突的锁定文件。

【讨论】:

    【解决方案2】:

    这可能并不理想,但您可以在项目根目录下运行 .js 文件来进行这些检查...

    你可以在你的项目根目录创建一个名为yarnpm.js(或其他)的文件,然后在你的package.jsondeploy命令中调用该文件..

    // package.json (trimmed)
    "scripts": {
      "deploy": "node yarnpm",
      "build": "whatever build command you use"
    },
    
    // yarnpm.js
    const fs = require('fs');
    
    const FILE_NAME = process.argv[1].replace(/^.*[\\\/]/, '');
    
    // Command you wish to run with `{{}}` in place of `npm` or `yarn'
    // This would allow you to easily run multiple `npm`/`yarn` commands without much work
    // For example, `{{}} run one && {{}} run two
    const COMMAND_TO_RUN = '{{}} run build; ./deploy.sh';
    
    try {
      if (fs.existsSync('./package-lock.json')) {  // Check for `npm`
        execute(COMMAND_TO_RUN.replace('{{}}', 'npm'));
      } else if (fs.existsSync('./yarn.lock')) {   // Check for `yarn`
        execute(COMMAND_TO_RUN.replace('{{}}', 'yarn'));
      } else {
        console.log('\x1b[33m', `[${FILE_NAME}] Unable to locate either npm or yarn!`, '\033[0m');
      }
    } catch (err) {
      console.log('\x1b[31m', `[${FILE_NAME}] Unable to deploy!`, '\033[0m');
    }
    
    function execute(command) { // Helper function, to make running `exec` easier
      require('child_process').exec(command,
        (error, stdout, stderr) => {
          if (error) {
            console.log(`error: ${error.message}`);
            return;
          }
          if (stderr) {
            console.log(`stderr: ${stderr}`);
            return;
          }
          console.log(stdout);
        });
    }
    

    希望这在某种程度上有所帮助!干杯。


    编辑:

    ...或者如果您想参数化 yarnpm.js 脚​​本,使其易于重复使用,并将所有“命令”保留在 package.json 文件中,您可以执行以下操作..

    // package.json (trimmed, parameterized)
    "scripts": {
        "deploy": "node yarnpm '{{}} run build; ./deploy.sh'",
        "build": "node build.js"
    },
    
    // yarnpm.js (parameterized)
    const COMMAND_TO_RUN = process.argv[2]; // Technically, the first 'parameter' is the third index
    const FILE_NAME = process.argv[1].replace(/^.*[\\\/]/, '');
    
    if (COMMAND_TO_RUN) {
      const fs = require('fs');
    
      try {
        if (fs.existsSync('./package-lock.json')) {  // Check for `npm`
          execute(COMMAND_TO_RUN.replace('{{}}', 'npm'));
        } else if (fs.existsSync('./yarn.lock')) {   // Check for `yarn`
          execute(COMMAND_TO_RUN.replace('{{}}', 'yarn'));
        } else {
          console.log('\x1b[33m', `[${FILE_NAME}] Unable to locate either npm or yarn!`, '\033[0m');
        }
      } catch (err) {
        console.log('\x1b[31m', `[${FILE_NAME}] Unable to deploy!`, '\033[0m');
      }
    
      function execute(command) { // Helper function, to make running `exec` easier
        require('child_process').exec(command,
          (error, stdout, stderr) => {
            if (error) {
              console.log(`error: ${error.message}`);
              return;
            }
            if (stderr) {
              console.log(`stderr: ${stderr}`);
              return;
            }
            console.log(stdout);
          });
      }
    } else {
      console.log('\x1b[31m', `[${FILE_NAME}] Requires a single argument!`, '\033[0m')
    }
    

    【讨论】:

      【解决方案3】:

      如果在运行前检查呢?

      您可以创建一个名为build.sh 的新文件,其内容如下:

      # check if current user installed node environment, if not, auto install it.
      if command -v node >/dev/null 2>&1; then
          echo "version of node: $(node -v)"
          echo "version of npm: $(npm -v)"
      else
          # auto install node environment, suppose platform is centos, 
          # need change this part to apply other platform.
          curl --silent --location https://rpm.nodesource.com/setup_12.x | sudo bash -
          yum -y install nodejs
      fi
      
      npm run build
      
      

      那么你的脚本将是:

      {
        "deploy": "./build.sh && ./deploy.sh"
      }
      

      【讨论】:

      • 嗯,我真的不喜欢在构建脚本中自动安装节点的想法。似乎完全令人惊讶,并且容易以意想不到的方式扰乱某人的系统。
      【解决方案4】:

      所以我想我有一个更简单的解决方案:

      "deploy": "yarn run build || npm run build; ./deploy.sh",
      

      它唯一真正的缺点是在 yarn 存在但构建失败的情况下,那么npm run build 也会发生。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-03
        • 2018-04-21
        • 1970-01-01
        • 2017-05-29
        • 1970-01-01
        • 2019-04-13
        • 2018-05-04
        相关资源
        最近更新 更多