1. 源码简介
官网简介:Install package programmatically. Detect package managers automatically (npm, yarn and pnpm)
简单理解,就是用于检查包管理器,自动安装依赖。
2. 使用
npm i @antfu/install-pkg
import { installPackage } from '@antfu/install-pkg'
await installPackage('vite', { silent: true })
3. 读源码
从入口 src/index.ts进去看,只对外暴露了两个文件,detect.ts 和 install.ts,意为探测和安装,功能职责划分得很明显。
先看看detect.ts,非常简短的代码,其中 find-up 这个包是用来查找文件路径。
这段代码意思很简单,根据当前目录lock文件,返回它是哪个类型的包管理器(npm | pnpm | yarn)。
import path from 'path'
import findUp from 'find-up'
export type PackageManager = 'pnpm' | 'yarn' | 'npm'
const LOCKS: Record<string, PackageManager> = {
'pnpm-lock.yaml': 'pnpm',
'yarn.lock': 'yarn',
'package-lock.json': 'npm',
}
/**
* @params cwd: current working directory
*/
export async function detectPackageManager(cwd = process.cwd()) {
// /Users/install-pkg/pnpm-lock.yaml
const result = await findUp(Object.keys(LOCKS), { cwd })
// pnpm
const agent = (result ? LOCKS[path.basename(result)] : null)
return agent
}
再看看install.ts,最终结果是用到了 execa 这个包用来执行脚本。
import execa from 'execa'
import { detectPackageManager } from '.'
export interface InstallPackageOptions {
// 目录路径
cwd?: string
// 安装包是开发还是生产
dev?: boolean
// stdio
silent?: boolean
// 指定包管理
packageManager?: string
// 离线安装模式, --prefer-offline 优先使用缓存数据
preferOffline?: boolean
// 额外参数
additionalArgs?: string[]
}
export async function installPackage(names: string | string[], options: InstallPackageOptions = {}) {
const agent = options.packageManager || await detectPackageManager(options.cwd) || 'npm'
if (!Array.isArray(names))
names = [names]
const args = options.additionalArgs || []
// npm 提供了离线安装模式,使用 --offline, --prefer-offline, --prefer-online 可以指定离线模式。
if (options.preferOffline)
args.unshift('--prefer-offline')
// 最终执行命令类似于 pnpm install -D --prefer-offine release-it react antd
return execa(
agent,
[
agent === 'yarn'
? 'add'
: 'install',
options.dev ? '-D' : '',
...args,
...names,
].filter(Boolean),
{
// https://nodejs.org/api/child_process.html#optionsstdio
stdio: options.silent ? 'ignore' : 'inherit',
cwd: options.cwd,
},
)
}