返回顶部
首页 > 资讯 > 前端开发 > JavaScript >编程式安装依赖install-pkg源码解析
  • 338
分享到

编程式安装依赖install-pkg源码解析

编程式安装依赖install-pkginstall pkg 2022-12-25 12:12:27 338人浏览 八月长安
摘要

目录正文使用源码分析总结正文 通常安装依赖都是通过命令式的方式来安装,有没有想过可以通过编程式的方式来安装依赖呢? install-pkg是一个用于安装依赖的工具,它可以在不同的环境

正文

通常安装依赖都是通过命令式的方式来安装,有没有想过可以通过编程式的方式来安装依赖呢?

install-pkg是一个用于安装依赖的工具,它可以在不同的环境下安装依赖,比如 npm、yarn、pnpm 等。

源码地址:GitHub.com/antfu/insta…

使用

install-pkg的使用非常简单,根据README的说明,就通过下面的代码就可以安装依赖了:

import { install } from 'install-pkg'
await installPackage('vite', { silent: true })

源码分析

install-pkg的源码非常简单,只有 100 行左右,我们来看看它的实现原理。

根据README的说明,我们可以通过installPackage方法来安装依赖,那么我们先来看看installPackage方法的实现:

installPackage方法在src/index.ts文件中,转成 js 代码如下:

import execa from 'execa'
import { detectPackageManager } from '.'
export async function installPackage(names, options = {}) {
  const detectedAgent = options.packageManager || await detectPackageManager(options.cwd) || 'npm'
  const [agent] = detectedAgent.split('@')
  if (!Array.isArray(names))
    names = [names]
  const args = options.additionalArgs || []
  if (options.preferOffline) {
    // yarn berry uses --cached option instead of --prefer-offline
    if (detectedAgent === 'yarn@berry')
      args.unshift('--cached')
    else
      args.unshift('--prefer-offline')
  }
  return execa(
    agent,
    [
      agent === 'yarn'
        ? 'add'
        : 'install',
      options.dev ? '-D' : '',
      ...args,
      ...names,
    ].filter(Boolean),
    {
      stdio: options.silent ? 'ignore' : 'inherit',
      cwd: options.cwd,
    },
  )
}

可以看到是一个异步方法,它接收两个参数,第一个参数是要安装的依赖名称,第二个参数是配置项。

在方法内部,首先通过传入的配置项options来获取packageManager,如果没有传入packageManager,则通过detectPackageManager方法来获取packageManager,如果detectPackageManager方法也没有获取到packageManager,则默认使用npm

来看看detectPackageManager方法的实现:

import fs from 'fs'
import path from 'path'
import findUp from 'find-up'
const AGENTS = ['pnpm', 'yarn', 'npm', 'pnpm@6', 'yarn@berry', 'bun']
const LOCKS = {
  'bun.lockb': 'bun',
  'pnpm-lock.yaml': 'pnpm',
  'yarn.lock': 'yarn',
  'package-lock.JSON': 'npm',
  'npm-shrinkwrap.json': 'npm',
}
export async function detectPackageManager(cwd = process.cwd()) {
  let agent = null
  const lockPath = await findUp(Object.keys(LOCKS), { cwd })
  let packageJsonPath
  if (lockPath)
    packageJsonPath = path.resolve(lockPath, '../package.json')
  else
    packageJsonPath = await findUp('package.json', { cwd })
  if (packageJsonPath && fs.existsSync(packageJsonPath)) {
    try {
      const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
      if (typeof pkg.packageManager === 'string') {
        const [name, version] = pkg.packageManager.split('@')
        if (name === 'yarn' && parseInt(version) > 1)
          agent = 'yarn@berry'
        else if (name === 'pnpm' && parseInt(version) < 7)
          agent = 'pnpm@6'
        else if (name in AGENTS)
          agent = name
        else
          console.warn('[ni] Unknown packageManager:', pkg.packageManager)
      }
    }
    catch {}
  }
  // detect based on lock
  if (!agent && lockPath)
    agent = LOCKS[path.basename(lockPath)]
  return agent
}

findUp是一个用于查找文件的工具,它可以从当前目录向上查找文件,直到找到为止。

我们来逐行分析:

const lockPath = await findUp(Object.keys(LOCKS), {cwd})
let packageJsonPath
if (lockPath)
    packageJsonPath = path.resolve(lockPath, '../package.json')
else
    packageJsonPath = await findUp('package.json', {cwd})

最开始是获取package-lock.jsonyarn.lockpnpm-lock.yaml等文件的路径;

如果找到就好办了,直接在这个文件目录下找package.json文件即可;

如果没找到就继续使用findUp方法来查找package.json文件。

if (packageJsonPath &amp;&amp; fs.existsSync(packageJsonPath)) {
    try {
        const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
        // ...
    } catch {
    }
}

如果找到了package.json文件,就读取文件内容,然后解析成 JSON 对象。

if (typeof pkg.packageManager === 'string') {
    const [name, version] = pkg.packageManager.split('@')
    if (name === 'yarn' && parseInt(version) > 1)
        agent = 'yarn@berry'
    else if (name === 'pnpm' && parseInt(version) < 7)
        agent = 'pnpm@6'
    else if (name in AGENTS)
        agent = name
    else
        console.warn('[ni] Unknown packageManager:', pkg.packageManager)
}

这里是用过packageManager来判断使用哪个包管理器;

  • 如果packageManageryarn,并且版本号大于1,则使用yarn@berry
  • 如果packageManagerpnpm,并且版本号小于7,则使用pnpm@6
  • 如果packageManageryarnpnpmnpmbun中的一个,则直接使用;
  • 否则就打印一个警告。
// detect based on lock
if (!agent && lockPath)
    agent = LOCKS[path.basename(lockPath)]

如果没有通过package.json来获取packageManager,则通过lockPath来获取packageManager

这个方法的核心就是通过两个方式来获取packageManager

  • 通过package.json中的packageManager字段;
  • 通过lock文件来获取。

可以说是非常巧妙。

我们继续看installPackage方法:

const detectedAgent = options.packageManager || await detectPackageManager(options.cwd) || 'npm'
const [agent] = detectedAgent.split('@')

这里是第一行,就是获取packageManager,和上面讲的方法相辅相成,继续往下看:

if (!Array.isArray(names))
    names = [names]

这里是将name统一变成数组,方便后面处理。

const args = options.additionalArgs || []
if (options.preferOffline) {
    // yarn berry uses --cached option instead of --prefer-offline
    if (detectedAgent === 'yarn@berry')
        args.unshift('--cached')
    else
        args.unshift('--prefer-offline')
}

这里是处理preferOffline参数,如果设置了这个参数,就会在args中添加--prefer-offline或者--cached参数,因为yarn@berrynpm的参数不一样。

return execa(
    agent,
    [
      agent === 'yarn'
        ? 'add'
        : 'install',
      options.dev ? '-D' : '',
      ...args,
      ...names,
    ].filter(Boolean),
    {
      stdio: options.silent ? 'ignore' : 'inherit',
      cwd: options.cwd,
    },
  )

这里的命令是根据packageManager来拼接的,yarnnpm的命令不一样,所以需要判断一下。

最后就是执行安装命令了,这里使用了execa来执行命令,这个库的用法和child_process差不多,但是更加方便,参考:execa。

总结

通过学习这个库,我们可以学到很多东西,比如:

  • 如何判断用户使用的包管理器;
  • 如何查找文件;
  • 如何使用execa来执行命令。

同时这里面还穿插着很多node的知识和包管理器的知识,比如:

  • nodepath.basename方法;
  • 包管理器的lock文件;
  • 包管理器的参数和命令。

以上就是编程式安装依赖install-pkg源码解析的详细内容,更多关于编程式安装依赖install-pkg的资料请关注编程网其它相关文章!

--结束END--

本文标题: 编程式安装依赖install-pkg源码解析

本文链接: https://lsjlt.com/news/175764.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 编程式安装依赖install-pkg源码解析
    目录正文使用源码分析总结正文 通常安装依赖都是通过命令式的方式来安装,有没有想过可以通过编程式的方式来安装依赖呢? install-pkg是一个用于安装依赖的工具,它可以在不同的环境...
    99+
    2022-12-25
    编程式安装依赖install-pkg install pkg
  • SpringBoot依赖管理的源码解析
    目录一. 依赖管理Ⅰ. 部分dependency导入时为啥不需要指定版本?1.1 父依赖启动器的工作1.2 问题答案Ⅱ. 项目运行依赖的JAR包是从何而来的2.1 分析源码2.2 问...
    99+
    2023-05-18
    SpringBoot 依赖管理 SpringBoot 源码
  • Vue安装依赖npm install时报错如何解决
    本篇内容介绍了“Vue安装依赖npm install时报错如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!安装依赖npm i...
    99+
    2023-06-30
  • Spring源码解析之循环依赖的实现流程
    目录前言循环依赖实现流程前言 上篇文章中我们分析完了Spring中Bean的实例化过程,但是没有对循环依赖的问题进行分析,这篇文章中我们来看一下spring是如何解决循环依赖的实现。...
    99+
    2024-04-02
  • ASP编程中如何使用npm安装依赖项?
    在ASP编程中,使用npm安装依赖项是非常常见的操作。npm是Node.js的包管理器,它允许我们轻松地安装、更新和卸载各种依赖项,使开发过程更加高效和便捷。 在本文中,我们将介绍如何使用npm在ASP编程中安装依赖项,并演示一些代码示例...
    99+
    2023-11-13
    编程算法 npm numpy
  • Spring源码解析之编程式事务
    目录一、前言二、编程式事务解析三、编程式事务示例四、TransactionCallback五、TransactionCallbackWithoutResult一、前言 在Sprin...
    99+
    2024-04-02
  • MySQL5.6源码编译安装的流程
    本篇内容主要讲解“MySQL5.6源码编译安装的流程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL5.6源码编译安装的流程”吧! ...
    99+
    2024-04-02
  • MySQL5.7.16源码编译安装的过程
    这篇文章主要讲解了“MySQL5.7.16源码编译安装的过程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“MySQL5.7.16源码编译安装的过程”吧!安装...
    99+
    2024-04-02
  • VS2022编译安装Qt6.5源码教程
    目录一、准备环境二、下载Qt 6.5源码三、解压四、编译、安装一、准备环境 包括安装VS2022,Windows SDK,Python3,这里就不再一一介绍了,需要说明的一点是还需要...
    99+
    2023-05-20
    VS2022编译安装Qt6.5源码 VS2022安装Qt6.5源码
  • Vue3 编译流程-源码解析
    前言: Vue3 发布已经很长一段时间了,最近也有机会在公司项目中用上了 Vue3 + TypeScript + Vite 的技术栈,所以闲暇之余抽空也在抽空阅读 Vue3 的源码。...
    99+
    2024-04-02
  • 如何使用npm在Linux上安装ASP编程所需的依赖?
    在Linux上进行ASP编程需要安装一些依赖,其中最重要的工具是npm。npm是Node.js的包管理器,可以让您轻松地安装、升级和删除软件包。在本文中,我们将介绍如何使用npm在Linux上安装ASP编程所需的依赖。 步骤1:安装Node...
    99+
    2023-06-04
    编程算法 npm linux
  • Vue 响应式系统依赖收集过程原理解析
    目录背景目标源码解读入口函数:observeclass ObserverObserve 如何处理数组Observe 如何处理对象class DepDep.targetclass Wa...
    99+
    2024-04-02
  • Nginx源码编译安装的示例分析
    这篇文章将为大家详细讲解有关Nginx源码编译安装的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。rpm包安装比较简单,这里不做说明。对于大多数开源软件,如果找不到安装包,可以使用源码安装方式,源...
    99+
    2023-06-25
  • 【2023.4.19】重新安装 Cocoapods 解决 pod install 卡住或者 cocoapods 依赖无法更新等问题
    重新安装 Cocoapods(2023.4.19) 做ios或flutter开发时,经常会遇到添加依赖过后pod install卡住,或者其他的一些奇奇怪怪的问题,如果花了很长时间都没有解决的话可以试...
    99+
    2023-09-15
    cocoapods ios flutter android-studio android
  • Spring源码解析之编程式事务的示例分析
    这篇文章主要为大家展示了“Spring源码解析之编程式事务的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Spring源码解析之编程式事务的示例分析”这篇文章吧。一、前言在Spring中...
    99+
    2023-06-15
  • 红帽mysql5.6源码编译安装过程
    操作系统more /etc/centos-release CentOS release 6.8 (Final)mysql5.6.44版本获取https://dev.mysql.com/get/Downloa...
    99+
    2024-04-02
  • Nginx源码编译安装过程记录
    rpm包安装比较简单,这里不做说明。 对于大多数开源软件,如果找不到安装包,可以使用源码安装方式,源码安装虽然没有yum、apt等工具方便,但是非常通用,在不同架构的cpu、不同操作...
    99+
    2024-04-02
  • 源码编译安装MySQL 5.7.9的过程
    这篇文章主要介绍“源码编译安装MySQL 5.7.9的过程”,在日常操作中,相信很多人在源码编译安装MySQL 5.7.9的过程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”源码编译安装MySQL 5.7.9...
    99+
    2023-06-01
  • Ubuntu源码编译安装Apache的教程
    这篇文章主要讲解了“Ubuntu源码编译安装Apache的教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Ubuntu源码编译安装Apache的教程”吧!apache 安装指南:http:...
    99+
    2023-06-05
  • 源代码编译安装PHP PDO MySQL:详细步骤解析
    源代码编译安装PHP PDO MySQL:详细步骤解析 在搭建Web服务器的过程中,PHP和MySQL是两个不可或缺的重要组件。而PHP的PDO扩展(PHP Data Objects)...
    99+
    2024-03-07
    编译 源代码 安装。
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作