源码共读 only-allow

236 阅读1分钟
  • what 一个能限制当前项目使用的包管理器的npm包
  • why 用于规范团队开发流程,避免成员之间开发时,因为使用不同的包管理器而引发的一些问题
  • how
"scripts": { 
    "preinstall": "npx only-allow 你希望的包管理器"
}
  • 源码解析

源码不长就36行代码,每行代码的解析都以注释的形式给出

#!/usr/bin/env node
const whichPMRuns = require('which-pm-runs') // 根据 process.env.npm_config_user_agent 获取当前是啥包管理器
const boxen = require('boxen') // 可以在控制台输出特定样式的矩形,相当于一个输出美化的工具

// 获取用户输入的参数,这里第一个一般是node  第二个是 当前运行脚本的名称 其余的都是用户输入的参数
const argv = process.argv.slice(2)
// 用户未输入直接退出
if (argv.length === 0) {
  console.log(
    'Please specify the wanted package manager: only-allow <npm|pnpm|yarn>'
  )
  process.exit(1)
}
// 获取用户希望使用的包管理器
const wantedPM = argv[0]
// 判断用户希望的包管理器是否合法, 不合法直接退出
// 这里是否可以将合法的包管理器定义为枚举 或者定义成常量数组然后 arr.some一下语义性与维护性会更好
if (wantedPM !== 'npm' && wantedPM !== 'pnpm' && wantedPM !== 'yarn') {
  console.log(
    `"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.`
  )
  process.exit(1)
}
// 根据 whichPMRuns 获取当前用户实际使用的包管理器
const usedPM = whichPMRuns()
// 对 usedPM 做一次异常处理,并且判断实际使用的包管理器是否与用户希望的一致
if (usedPM && usedPM.name !== wantedPM) {
  // 定义格式化输出的样式
  const boxenOpts = { borderColor: 'red', borderStyle: 'double', padding: 1 }
  // 根据不同类型的包管理器,给出不同的提示
  // 这里的代码能否改为ts的枚举,这样可以避免打错字母或者漏分支等低级错误
  switch (wantedPM) {
    case 'npm':
      // 这里的代码过于冗余,基本一样的代码写了3份,坏味道比较浓
      // 能否在分支中只定义需要提示的文案,最后统一console.log
      console.log(
        boxen('Use "npm install" for installation in this project', boxenOpts)
      )
      break
    case 'pnpm':
      console.log(
        boxen(
          `Use "pnpm install" for installation in this project.

If you don't have pnpm, install it via "npm i -g pnpm".
For more details, go to https://pnpm.js.org/`,
          boxenOpts
        )
      )
      break
    case 'yarn':
      console.log(
        boxen(
          `Use "yarn" for installation in this project.

If you don't have Yarn, install it via "npm i -g yarn".
For more details, go to https://yarnpkg.com/`,
          boxenOpts
        )
      )
      break
  }
  process.exit(1)
}
  • ts 改良版

看源码过程中发现很多地方可以进行优化,就顺手使用ts进行了一次简单重构

#!/usr/bin/env node
import whichPMRuns from 'which-pm-runs'
import boxen, { Options, BorderStyle } from 'boxen'

/** 合法的包管理工具 */
enum LegalPMEnum {
    npm = 'npm',
    pnpm = 'pnpm',
    yarn = 'yarn',
}

const argv = process.argv.slice(2)
if (argv.length === 0) {
  console.log('Please specify the wanted package manager: only-allow <npm|pnpm|yarn>')
  process.exit(1)
}
const wantedPM = argv[0] as LegalPMEnum
const LegalPMArr = [LegalPMEnum.npm, LegalPMEnum.pnpm, LegalPMEnum.yarn]
if (LegalPMArr.every(item => item !== wantedPM)) {
  console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.`)
  process.exit(1)
}
const usedPM = whichPMRuns()
if (usedPM && usedPM.name !== wantedPM) {
  let errMsg = ''
  switch (wantedPM) {
    case LegalPMEnum.npm:
        errMsg = 'Use "npm install" for installation in this project'
        break
    case LegalPMEnum.pnpm:
        errMsg = `Use "pnpm install" for installation in this project.
                    If you don't have pnpm, install it via "npm i -g pnpm".
                    For more details, go to https://pnpm.js.org/`;
      break
    case LegalPMEnum.yarn:
        errMsg = `Use "yarn" for installation in this project.
                    If you don't have Yarn, install it via "npm i -g yarn".
                    For more details, go to https://yarnpkg.com/`
      break;
    default: 
      const n: never = wantedPM
  }
  const boxenOpts: Options = { borderColor: 'red', borderStyle: BorderStyle.Double, padding: 1 }
  console.log(boxen(errMsg,boxenOpts))
  process.exit(1)
}