【问题标题】:Automatic npm install --legacy-peer-deps for a single dependency单个依赖项的自动 npm install --legacy-peer-deps
【发布时间】:2021-11-28 10:59:20
【问题描述】:

假设我有一个像这样的package.json

{
  "name": "my-app",
  "version": "0.1.0",
  "dependencies": {
    "@aws-sdk/client-s3": "^3.21.0",
    "@testing-library/react": "^11.2.5",
    "axios": "^0.22.0",
    "credit-card-type": "^8.3.0",
    "csstype": "^3.0.8",
    "dayjs": "^1.10.4",
    "lodash": "^4.17.20",
    "mathjax-full": "^3.2.0",
    "mathjax-react": "^1.0.6",
    "react": "^17.0.2",
  },
  "proxy": "http://localhost:5000",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "jest",
    "eject": "react-scripts eject",
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

问题是依赖mathjax-react & mathjax-full 需要react@"^15.0.0 || ^16.0.0"。我已经用npm i --forcenpm i --legacy-peer-deps 进行了测试,这一切似乎都适用于我的反应版本react@17.0.2

我不想在每次需要安装依赖项时都运行 npm i --forcenpm i --legacy-peer-deps,所以我一直在寻找一种方法来自动为 mathjax-reactmathjax-full 执行此操作,只要我运行npm i。我尝试查看.npmrc docs 和这个reference,但找不到这样做的方法。这可能是什么解决方案?是否有针对此的原生 npm 解决方案?还是我必须编写一个脚本来读取我的package.json 并为每个依赖项单独运行npm install

我的理由是,如果我需要安装一些其他有冲突的依赖项,我永远不会被警告。

【问题讨论】:

    标签: npm dependencies dependency-management


    【解决方案1】:

    好的,经过大量的头部撞击。我想出了这个:

    第 1 步

    将此文件添加到您机器的任何位置:

    npm.sh

    #!/usr/bin/bash
    npm() {
     NPM_PATH=$(which npm)
     CURR_PATH=$(pwd)
     NO_NPM_I="$CURR_PATH/.nonpminstall"
    
     if [ "$1" = "i" ] || [ "$1" = "install" ]; then
       if [[ -f "$NO_NPM_I" ]]; then
         echo ""
         echo -e "\033[0;31mPLEASE USE:\033[0m \033[0;33m\"npm run install\"\033[0m"
       else
         "$NPM_PATH" "$@"
       fi
      else
        "$NPM_PATH" "$@"
     fi
    }
    

    如果当前目录中有.nonpminstall 文件,这将覆盖npm inpm install。 您还需要将源添加到您的~/.bash_profile

    ~/.bash_profile

    source path/to/your/script/npm.sh
    

    然后运行source ~/.bash_profile

    第 2 步

    将此添加到您的package.json

    {
        ...
        "scripts": {
            "i": "node relative/path/from/your/projectroot/installDependencies.js",
            "install": "node relative/path/from/your/projectroot/installDependencies.js",
        }
    }
    

    第 3 步

    将此添加到您的package.json

    {
        ...
        "conflictDependencies": {
            "mathjax-full": "^3.2.0",
            "@ckeditor/ckeditor5-react": "^3.0.3",
            "@sentry/react": "^6.12.0",
            "@sentry/tracing": "^6.12.0"
        }
    }
    

    这些依赖将与npm i <pkg> --force分开安装

    第 4 步

    installDependencies.js

    代码

    const { execSync } = require('child_process');
    const pkg = require('#root/package.json');
    const fs = require('fs');
    
    const {
      dependencies,
      devDependencies,
      conflictDependencies,
    } = pkg;
    
    const conflictDepNames = Object.keys(conflictDependencies);
    
    class Memo {
      static memo = [];
      static memoTemp = [];
      static pkg = {};
    }
    
    /**
     * Saves the package.json in memory
     * because npm compains about --legacy-peer-deps
     * if there is a package.json file
     */
    function pkgJsonMemoStart() {
      try {
        Memo.pkg = pkg;
        fs.unlinkSync('./package.json')
      } catch (error) {
        console.log(error);
        process.exit(1)
      }
    }
    
    /**
     * Temporarily erases the package.json
     */
    function pkgJsonMemoSave() {
      try {
        includeNewDeps();
        fs.writeFileSync('./package.json', JSON.stringify(Memo.pkg, null, 2))
      } catch (error) {
        console.error(error);
        console.log('There was a problem writing your package.json, here you go!');
        // console.log(Memo.pkg);
        process.exit(1);
      }
    }
    
    /**
     * Writes the full npm log to disk
     */
    function writeLogs() {
      const log = Memo.memo.join('\n')
      fs.writeFileSync('depInstallLog.log', log)
      process.exit();
    }
    
    /**
     * Adds new installed dependencies to package.json
     */
    function includeNewDeps() {
      try {
        const newDeps = JSON.parse(fs.readFileSync('./package.json'));    
        Memo.pkg = {
          ...Memo.pkg,
          devDependencies: {
            ...Memo.pkg.devDependencies,
            ...newDeps.devDependencies,
          },
          dependencies: {
            ...Memo.pkg.dependencies,
            ...newDeps.dependencies,
          },
        }
    
      } catch (error) {
        console.error(error);
        console.log('There was a problem reading your package.json, here you go!');
        // console.log(Memo.pkg);
      }
    }
    
    /**
     * Handles the instalation
     * package by package
     * @param {*} param0 
     */
    function npmInstall({deps, prefix = '', suffix = ''}) {
      for (dep of deps){
          const isWindows =  /^win/.test(process.platform)
          const npm = isWindows ? 'npm.cmd' : 'npm'
          process.stdout.write(`\nInstalling: ${dep}`);
          
          const arg = ['i', prefix, dep, suffix]
            .filter(a =>  a !== '');
    
          const res = execSync([npm, ...arg].join(' ')).toString();
          Memo.memo.push(`\x1b[33m#### ${dep.toUpperCase().split('@')[0]} ####\x1b[0m`)
          Memo.memo.push(res)
    
          Memo.memoTemp.push(`\x1b[33m#### ${dep.toUpperCase().split('@')[0]} ####\x1b[0m`)
          Memo.memoTemp.push(res)
    
          if(res.stderr) {
             console.error('\x1b[31mFAIL❌\x1b[0m', `${res.stderr}`)
             throw res.stderr.toString();
          };
    
          process.stdout.write('\x1b[32m OK ✔\x1b[0m')
    
          process.on('SIGINT', () => {
            // eslint-disable-next-line no-console
            console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
            pkgJsonMemoSave();
          });
          
      }
      console.log('\n');
      const log = Memo.memoTemp.join('\n')
      console.log(log);
      Memo.memoTemp = [];
    
      process.on('SIGINT', () => {
        // eslint-disable-next-line no-console
        console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
        pkgJsonMemoSave();
        writeLogs();
      });
      
    }
    
    /**
     * Install the non conflicting packages
     */
    function installNormal() {
      const normalInstallDeps = Object.entries(dependencies)
        .filter(([name, version]) => (!conflictDepNames.includes(name)))
        .map(([name, version]) => {
          if(/^github:/.test(version)) {
            return version
          }
          return [name, version].join('@')
        })
    
      console.log('\x1b[34m%s\x1b[0m', `
      ╭─────────────────────────────────────────╮
      │                                         │
      │ INSTALLING NON CONFLICTING DEPENDENCIES │
      │                                         │
      ╰─────────────────────────────────────────╯
      `)
    
    
      npmInstall({deps: normalInstallDeps});
    
    
      process.on('SIGINT', () => {
        // eslint-disable-next-line no-console
        console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
        pkgJsonMemoSave();
        writeLogs();
      });
      
    }
    
    /**
     * Installs the devDeps
     */
    function installDevDeps() {
      const devInstallDeps = Object.entries(devDependencies)
      .map(([name, version]) => {
        if(/^github:/.test(version)) {
          return version
        }
        return [name, version].join('@')
      })
    
      console.log('\x1b[33m%s\x1b[0m', `
      ╭─────────────────────────────────────────╮
      │                                         │
      │      INSTALLING DEV DEPENDENCIES        │
      │                                         │
      ╰─────────────────────────────────────────╯
      `)
    
      npmInstall({deps: devInstallDeps, prefix: '-D'});
    
    
      process.on('SIGINT', () => {
        // eslint-disable-next-line no-console
        console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
        pkgJsonMemoSave();
        writeLogs();
      });
      
    }
    
    /**
     * Installs the conflicting deps with --force
     */
    function installConflictDeps() {
    
      const forceInstallDeps = Object.entries(dependencies)
      .filter(([name, version]) => (conflictDepNames.includes(name)))
      .map(([name, version]) => {
        if(/^github:/.test(version)) {
          return version
        }
        return [name, version].join('@')
      })
    
      console.log('\x1b[31m%s\x1b[0m', `
      ╭─────────────────────────────────────────╮
      │                                         │
      │   INSTALLING CONFLICTING DEPENDENCIES   │
      │                                         │
      ╰─────────────────────────────────────────╯
      `)
    
      npmInstall({deps: forceInstallDeps, suffix: '--force'});
    
    
      process.on('SIGINT', () => {
        // eslint-disable-next-line no-console
        console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
        pkgJsonMemoSave();
        writeLogs();
      });
      
    }
    
    /**
     * Handles all package instalations with `npm run i` 
     * or `npm run install`
     */
    function install () {
      installNormal();
      installDevDeps();
      installConflictDeps();
    }
    
    /**
     * Checks the arguments and decides if
     * the user wants to install all packages or by name
     */
    function main() {
      try {
        pkgJsonMemoStart();
        const args = process.argv
        args.splice(0, 2)
        
        const prefixes = args.filter((a) => (/^-+/.test(a)));
        const deps = args.filter((a) => (!(/^-+/.test(a))));
    
        if(args.length === 0) install();
        else npmInstall({deps, prefix: prefixes.join(' ')});
    
        process.on('SIGINT', () => {
          // eslint-disable-next-line no-console
          console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
          pkgJsonMemoSave();
        });
        
      } catch (error) {
        console.error(error);
      } finally {
        pkgJsonMemoSave();
        writeLogs();
      }
    }
    
    main();
    
    process.on('SIGINT', () => {
      // eslint-disable-next-line no-console
      console.log('\nGracefully shutting down from SIGINT (Crtl-C)');
      pkgJsonMemoSave();
      writeLogs();
    });
    

    哦!顺便说一句,如果你想使用 installDependencies.js const pkg = require('#root/package.json'); 的第 2 行中的语法,你必须将它添加到你的 package.json

    {
        "imports": {
            "#root/*": "./*"
        },
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-07
      • 2021-07-18
      • 2021-05-20
      • 1970-01-01
      • 2022-11-10
      • 2020-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多