欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

編程式安裝依賴install-pkg源碼解析

 更新時間:2022年12月25日 08:45:54   作者:田八  
這篇文章主要為大家介紹了編程式安裝依賴install-pkg源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

通常安裝依賴都是通過命令式的方式來安裝,有沒有想過可以通過編程式的方式來安裝依賴呢?

install-pkg是一個用于安裝依賴的工具,它可以在不同的環(huán)境下安裝依賴,比如 npm、yarn、pnpm 等。

源碼地址:github.com/antfu/insta…

使用

install-pkg的使用非常簡單,根據(jù)README的說明,就通過下面的代碼就可以安裝依賴了:

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

源碼分析

install-pkg的源碼非常簡單,只有 100 行左右,我們來看看它的實現(xiàn)原理。

根據(jù)README的說明,我們可以通過installPackage方法來安裝依賴,那么我們先來看看installPackage方法的實現(xiàn):

installPackage方法在src/index.ts文件中,轉(zhuǎn)成 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,
    },
  )
}

可以看到是一個異步方法,它接收兩個參數(shù),第一個參數(shù)是要安裝的依賴名稱,第二個參數(shù)是配置項。

在方法內(nèi)部,首先通過傳入的配置項options來獲取packageManager,如果沒有傳入packageManager,則通過detectPackageManager方法來獲取packageManager,如果detectPackageManager方法也沒有獲取到packageManager,則默認使用npm。

來看看detectPackageManager方法的實現(xiàn):

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.json、yarn.lock、pnpm-lock.yaml等文件的路徑;

如果找到就好辦了,直接在這個文件目錄下找package.json文件即可;

如果沒找到就繼續(xù)使用findUp方法來查找package.json文件。

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

如果找到了package.json文件,就讀取文件內(nèi)容,然后解析成 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;
  • 如果packageManageryarn、pnpm、npm、bun中的一個,則直接使用;
  • 否則就打印一個警告。
// detect based on lock
if (!agent && lockPath)
    agent = LOCKS[path.basename(lockPath)]

如果沒有通過package.json來獲取packageManager,則通過lockPath來獲取packageManager。

這個方法的核心就是通過兩個方式來獲取packageManager

  • 通過package.json中的packageManager字段;
  • 通過lock文件來獲取。

可以說是非常巧妙。

我們繼續(xù)看installPackage方法:

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

這里是第一行,就是獲取packageManager,和上面講的方法相輔相成,繼續(xù)往下看:

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

這里是將name統(tǒng)一變成數(shù)組,方便后面處理。

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參數(shù),如果設置了這個參數(shù),就會在args中添加--prefer-offline或者--cached參數(shù),因為yarn@berrynpm的參數(shù)不一樣。

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

這里的命令是根據(jù)packageManager來拼接的,yarnnpm的命令不一樣,所以需要判斷一下。

最后就是執(zhí)行安裝命令了,這里使用了execa來執(zhí)行命令,這個庫的用法和child_process差不多,但是更加方便,參考:execa。

總結(jié)

通過學習這個庫,我們可以學到很多東西,比如:

  • 如何判斷用戶使用的包管理器;
  • 如何查找文件;
  • 如何使用execa來執(zhí)行命令。

同時這里面還穿插著很多node的知識和包管理器的知識,比如:

  • nodepath.basename方法;
  • 包管理器的lock文件;
  • 包管理器的參數(shù)和命令。

以上就是編程式安裝依賴install-pkg源碼解析的詳細內(nèi)容,更多關于編程式安裝依賴install-pkg的資料請關注腳本之家其它相關文章!

相關文章

  • JavaScript知識:構(gòu)造函數(shù)也是函數(shù)

    JavaScript知識:構(gòu)造函數(shù)也是函數(shù)

    構(gòu)造函數(shù)就是初始化一個實例對象,對象的prototype屬性是繼承一個實例對象。本文給大家分享javascript構(gòu)造函數(shù)詳解,對js構(gòu)造函數(shù)相關知識感興趣的朋友一起學習吧
    2021-08-08
  • 微信小程序動態(tài)的加載數(shù)據(jù)實例代碼

    微信小程序動態(tài)的加載數(shù)據(jù)實例代碼

    這篇文章主要介紹了 微信小程序動態(tài)的加載數(shù)據(jù)實例代碼的相關資料,需要的朋友可以參考下
    2017-04-04
  • JavaScript選擇器函數(shù)querySelector和querySelectorAll

    JavaScript選擇器函數(shù)querySelector和querySelectorAll

    這篇文章主要介紹了?JavaScript選擇器函數(shù)querySelector和querySelectorAll,下面文章圍繞querySelector和querySelectorAll的相關資料展開詳細內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • 解析Clipboard?API剪貼板操作實例

    解析Clipboard?API剪貼板操作實例

    這篇文章主要為大家介紹了解析Clipboard?API剪貼板操作實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • Three.js添加陰影和簡單后期處理實現(xiàn)示例詳解

    Three.js添加陰影和簡單后期處理實現(xiàn)示例詳解

    這篇文章主要為大家介紹了Three.js添加陰影和簡單后期處理實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • JavaScript代碼不能被阻斷的穩(wěn)定性建設

    JavaScript代碼不能被阻斷的穩(wěn)定性建設

    這篇文章主要為大家介紹了JavaScript代碼不能被阻斷的穩(wěn)定性建設詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 用JS創(chuàng)建一個錄屏功能

    用JS創(chuàng)建一個錄屏功能

    這篇文章主要介紹了利用JS創(chuàng)建一個錄屏功能,創(chuàng)建這個功能錢我們首先創(chuàng)建一個HTML文件,包含記錄按鈕和一個播放標簽,下面來看看創(chuàng)建的詳細過程
    2021-11-11
  • JavaScript中MutationObServer監(jiān)聽DOM元素詳情

    JavaScript中MutationObServer監(jiān)聽DOM元素詳情

    這篇文章主要給大家分享的是?JavaScript中MutationObServer監(jiān)聽DOM元素詳情,DOM的MutationObServer接口,可以在DOM被修改時異步執(zhí)行回調(diào)函數(shù),我的理解就是可以監(jiān)聽DOM修改。下面來看看文章的詳細內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • Fabric.js?樣式不更新解決方法案例

    Fabric.js?樣式不更新解決方法案例

    這篇文章主要為大家介紹了Fabric.js?樣式不更新解決方法案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Web?Animations?API實現(xiàn)一個精確計時的時鐘示例

    Web?Animations?API實現(xiàn)一個精確計時的時鐘示例

    這篇文章主要為大家介紹了Web?Animations?API實現(xiàn)一個精確計時的時鐘示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07

最新評論