我正在参加「掘金·启航计划」
Install package programmatically. Detect package managers automatically (npm, yarn and pnpm).
以编程方式安装包。自动检测包管理器(npm、yarn 和 pnpm)。
源码
// install-pkg/src/install.ts
import execa from 'execa' // 执行脚本 对child_process的改进
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 = {}) {
// 如果没有指定包管理器,则自动探测所使用的包管理器
// 以上都没有,则使用npm
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, // 当前工作目录
},
)
// 如 pnpm install -D --prefer-offine release-it react antd
}
// install-pkg/src/detect.ts
import path from 'path'
import findUp from 'find-up'
// 只允许分配pnpm yarn npm
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()) {
// 查找目标文件并获取路径,返回第一个查找结果并返回promise,否则返回undefined
const result = await findUp(Object.keys(LOCKS), { cwd })
// 提取包管理器
const agent = (result ? LOCKS[path.basename(result)] : null)
return agent
}
部分工具或配置
execa.options.stdio
- pipe:相当于['pipe', 'pipe', 'pipe'],子进程的stdio和父进程的stdio通过管道进行连接
- ignore:相当于['ignore','ignore', 'ignore'],子进程的stdio绑定到/dev/null,丢弃数据的输入输出。
- inherit:继承父进程相关的stdio,等同于[process.stdin,process.stdout,process.sterr]或者[0,1,2],此时子进程的stdio都是绑定在同一个地方。
findUp
Find a file or directory by walking up parent directories
通过遍历父目录查找文件或目录
findUp([...name], 选项?)
返回获取到的第一个路径,如果没有,则为undefined
scripts
"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"
},
自动根据锁文件 yarn.lock / pnpm-lock.yaml / package-lock.json 检测使用 yarn / pnpm / npm 的包管理器。
TypeScript / ESNext node runtime powered by esbuild
使用 esbuild 即时传输TypeScript 和 esnext 功能
打包ts
交互式 CLI 可增加版本号等
github action workflows
GitHub的持续集成
之前在项目中有使用Jenkins做自动化部署,脚本的整体的结构有些类似
GitHub Action特别的地方在于可以引用官方或别人的action
第一次看起来倒有点像docker的感觉
Mark一下,有时间动手做个实践
// install-pkg/.github/workflows/release.yml
# workflow的名称
name: Release
# trigger push tags为vxxx时触发
on:
push:
tags:
- 'v*'
jobs:
release:
# 运行所需的虚拟机环境
runs-on: ubuntu-latest
steps:
# 第一步,使用checkout action拉取源码
- uses: actions/checkout@v2
with:
fetch-depth: 0
# 第二步,使用setup-node 安装node环境
- uses: actions/setup-node@v2
with:
node-version: '14'
registry-url: https://registry.npmjs.org/
# 执行一系列命令
# 全局安装pnpm @antfu/ni
- run: npm i -g pnpm @antfu/ni
# npm ci 不更新锁文件 --frozen-lockfile
- run: nci
# 若存在test命令则执行
- run: nr test --if-present
- run: npx conventional-github-releaser -p angular
env:
CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}}
总结
- 学习构建一个ts的npm包
- 学习GitHub action
- 学习findUp、execa、ni等的使用