本文是在看到 《Vue 团队核心成员开发的 39 行小工具 install-pkg 安装包,值得一学!》 文章后,对 @antfu/install-pkg 进行的一次源码阅读。
install-pkg 介绍
Install package programmatically. Detect package managers automatically (npm
, yarn
and pnpm
).
自动检测包管理器(npm、yarn 和 pnpm)来编程式安装包依赖。
1
| npm i @antfu/install-pkg
|
1 2 3
| import { installPackage } from '@antfu/install-pkg';
await installPackage('vite', { silent: true });
|
源码
入口文件 src/index.ts
导出所有
1 2
| export * from './detect'; export * from './install';
|
install.ts installPackage 安装包
支持指定包管理器,支持安装多个依赖,支持额外的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import execa from 'execa'; import { detectPackageManager } from '.';
export interface InstallPackageOptions { cwd?: string; dev?: boolean; silent?: boolean; packageManager?: string; 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 || [];
if (options.preferOffline) 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, } ); }
|
上述代码最终执行类似如下脚本:
1
| yarn add -D react react-dom
|
detect.ts detectPackageManager 包探测器
根据当前的锁文件(yarn.lock or package-lock.json or pnpm-lock.yaml )判断是哪个包管理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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', };
export async function detectPackageManager(cwd = process.cwd()) { const result = await findUp(Object.keys(LOCKS), { cwd }); const agent = result ? LOCKS[path.basename(result)] : null; return agent; }
|
其中需要注意的一些 node 相关的知识:
其中findUp为查找文件路径:
1 2 3 4 5 6 7 8
| / └── Users └── sindresorhus ├── unicorn.png └── foo └── bar ├── baz └── example.js
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import path from 'node:path'; import { findUp, pathExists } from 'find-up';
console.log(await findUp('unicorn.png'));
console.log(await findUp(['rainbow.png', 'unicorn.png']));
console.log( await findUp( async (directory) => { const hasUnicorns = await pathExists(path.join(directory, 'unicorn.png')); return hasUnicorns && directory; }, { type: 'directory' } ) );
|
所以在有yarn.lock
文件的项目中,detectPackageManager
函数最终返回 agent 的是yarn
。
至此,install-pkg
的源码已经看完,可以总结原理为:
通过 lock 文件自动检测,确定使用哪一个包管理器(npm、yarn、pnpm),最终用 execa 执行类似如下的命令。
1
| yarn add -D react react-dom
|
看完源码,我们也可以看下 package.json
中的 scripts
命令,学习一下。
package.json script 解析
1 2 3 4 5 6 7 8 9
| "scripts": { "prepublishOnly": "nr build", "dev": "nr build --watch", "start": "esno src/index.ts", "build": "tsup src/index.ts --format cjs,esm --dts --no-splitting", "release": "bumpp --commit --push --tag && pnpm publish", "lint": "eslint \"{src,test}/**/*.ts\"", "lint:fix": "nr lint -- --fix" }
|
nr? —-> ni 神器
github ni
推荐看尤雨溪推荐神器 ni ,能替代 npm/yarn/pnpm ?简单好用!源码揭秘!
可以自动根据锁文件 yarn.lock / pnpm-lock.yaml / package-lock.json
检测使用 yarn / pnpm / npm
的包管理器。
例子:
nr 交互式选择脚本
1 2 3 4 5 6 7 8 9 10
| nr # 交互式选择脚本 # interactively select the script to run # supports https://www.npmjs.com/package/npm-scripts-info convention
nr dev --port=3000
# npm run dev -- --port=3000 # yarn run dev --port=3000 # pnpm run dev -- --port=3000
|
nci - clean install
1 2 3 4 5
| nci # npm ci # 简单说就是不更新锁文件 # yarn install --frozen-lockfile # pnpm install --frozen-lockfile
|
等
esno
github esno
源码不多,如下所示:
1 2 3 4 5 6 7 8 9 10
| #!/usr/bin/env node
const spawn = require('cross-spawn'); const spawnSync = spawn.sync;
const register = require.resolve('esbuild-register');
const argv = process.argv.slice(2);
process.exit(spawnSync('node', ['-r', register, ...argv], { stdio: 'inherit' }).status);
|
esbuild-register 简单说:使用 esbuild 即时传输 JSX、TypeScript 和 esnext 功能
cross-spawn:编写跨平台 spawn 语句,可参考《用 Node 编写跨平台 spawn 语句》
tsup
打包 TypeScript
库的最简单、最快的方法。
tsup
bumpp 交互式提升版本号
bumpp
version-bump-prompt
交互式 CLI 可增加您的版本号等
总结
最后,在 install-pkg 上可查看本篇源码文章~
参考链接
- [Vue 团队核心成员开发的 39 行小工具 install-pkg 安装包,值得一学!](