1. 前言
大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。
本文倉庫 https://github.com/lxchuan12/install-pkg-analysis.git,求個star^_^[1]
源碼共讀活動 每周一期,已進行到16期。Vue團隊核心成員 Anthony Fu
開發的 install-pkg[2] 小工具,主文件源碼僅39行,非常值得我們學習。
閱讀本文,你將學到:
1.?如何學習調試源碼
2.?如何開發構建一個?ts?的?npm?包
3.?如何配置?github?action
4.?配置屬于自己的?eslint?預設、提升版本號等
5.?學會使用?execa?執行命令
6.?等等
2. install-pkg 是什么
Install package programmatically. Detect package managers automatically (npm
, yarn
and pnpm
).
以編程方式安裝包。自動檢測包管理器(npm
、yarn
和 pnpm
)。
npm?i?@antfu/install-pkg
import?{?installPackage?}?from?'@antfu/install-pkg'
await?installPackage('vite',?{?silent:?true?})
我們看看npmjs.com @antfu/install-pkg[3] 有哪些包依賴的這個包。
我們可以發現目前只有以下這兩個項目使用了。
unplugin-icons[4]@chenyueban/lint[5]
我們克隆項目來看源碼。
3 克隆項目
#?推薦克隆我的項目,保證與文章同步
git?clone?https://github.com/lxchuan12/install-pkg-analysis.git
#?npm?i?-g?pnpm
cd?install-pkg-analysis/install-pkg?&&?pnpm?i
#?VSCode?直接打開當前項目
#?code?.#?或者克隆官方項目
git?clone?https://github.com/antfu/install-pkg.git
#?npm?i?-g?pnpm
cd?install-pkg?&&?pnpm?i
#?VSCode?直接打開當前項目
#?code?.
看源碼一般先看 package.json
,再看 script
。
{"name":?"@antfu/install-pkg","version":?"0.1.0","scripts":?{"start":?"esno?src/index.ts"},
}
關于調試可以看我的這篇文章:新手向:前端程序員必學基本技能——調試JS代碼,這里就不再贅述了。
我們可以得知入口文件是 src/index.ts
src
文件夾下有三個文件
src
-?detect.ts
-?index.ts
-?install
接著我們看這些文件源碼。
4. 源碼
4.1 index.js
導出所有
//?src/install.ts
export?*?from?'./detect'
export?*?from?'./install'
我們來看 install.ts
文件,installPackage
方法。
4.2 installPackage 安裝包
//?src/install.ts
import?execa?from?'execa'
import?{?detectPackageManager?}?from?'.'export?interface?InstallPackageOptions?{cwd?:?stringdev?:?booleansilent?:?booleanpackageManager?:?stringpreferOffline?:?booleanadditionalArgs?:?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,},)
}
支持安裝多個,也支持指定包管理器,支持額外的參數。
其中 github execa[6] 是執行腳本
Process execution for humans
也就是說:最終執行類似以下的腳本。
pnpm?install?-D?--prefer-offine?release-it?react?antd
我們接著來看 detect.ts
文件 探測包管理器 detectPackageManager
函數如何實現的。
4.3 detectPackageManager 探測包管理器
根據當前目錄鎖文件,探測包管理器。
//?src/detect.ts
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
}
其中 find-up[7] 查找路徑。
/
└──?Users└──?install-pkg├──?pnpm-lock.yaml
import?{findUp}?from?'find-up';console.log(await?findUp('pnpm-lock.yaml'));
//=>?'/Users/install-pkg/pnpm-lock.yaml'
path.basename('/Users/install-pkg/pnpm-lock.yaml')
則是 pnpm-lock.yaml
。
所以在有pnpm-lock.yaml
文件的項目中,detectPackageManager
函數最終返回的是 pnpm
。
至此我們可以用一句話總結原理就是:通過鎖文件自動檢測使用何種包管理器(npm、yarn、pnpm),最終用 execa[8] 執行類似如下的命令。
pnpm?install?-D?--prefer-offine?release-it?react?antd
看完源碼,我們接著來解釋下 package.json
中的 scripts
命令。
5. package.json script 命令解析
{"name":?"@antfu/install-pkg","version":?"0.1.0","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"},
}
5.1 ni 神器
github ni[9]
我之前寫過源碼文章。
尤雨溪推薦神器 ni ,能替代 npm/yarn/pnpm ?簡單好用!源碼揭秘![10]
自動根據鎖文件 yarn.lock / pnpm-lock.yaml / package-lock.json 檢測使用 yarn / pnpm / npm 的包管理器。
nr?dev?--port=3000#?npm?run?dev?--?--port=3000
#?yarn?run?dev?--port=3000
#?pnpm?run?dev?--?--port=3000
nr
#?交互式選擇腳本
#?interactively?select?the?script?to?run
#?supports?https://www.npmjs.com/package/npm-scripts-info?convention
nci - clean install
nci
#?npm?ci
#?簡單說就是不更新鎖文件
#?yarn?install?--frozen-lockfile
#?pnpm?install?--frozen-lockfile
pnpm install --frozen-lockfile[11]
5.2 esno 運行 ts
esno[12]
TypeScript / ESNext node runtime powered by esbuild
源碼也不是很多。
#!/usr/bin/env?nodeconst?spawn?=?require('cross-spawn')
const?spawnSync?=?spawn.syncconst?register?=?require.resolve('esbuild-register')const?argv?=?process.argv.slice(2)process.exit(spawnSync('node',?['-r',?register,?...argv],?{?stdio:?'inherit'?}).status)
esbuild-register[13]簡單說:使用 esbuild 即時傳輸 JSX、TypeScript 和 esnext 功能
5.3 tsup 打包 ts
打包 TypeScript
庫的最簡單、最快的方法。
tsup[14]
5.4 bumpp 交互式提升版本號
bumpp[15]
version-bump-prompt[16]
交互式 CLI 可增加您的版本號等
5.5 eslint 預設
eslint 預設[17]
pnpm?add?-D?eslint?@antfu/eslint-config
添加 .eslintrc
文件
//?.eslintrc
{"extends":?["@antfu"],"rules":?{}
}
之前看其他源碼發現的也很好用的 eslint 工具 xo
xo[18]
JavaScript/TypeScript linter (ESLint wrapper) with great defaults JavaScript/TypeScript linter(ESLint 包裝器)具有很好的默認值
看完 scripts 命令解析,我們來看看 github action 配置。
6. github action workflows
對于github action 不熟悉的讀者,可以看阮一峰老師 GitHub Actions 入門教程[19]
配置文件workflows/release[20]
構建歷史github action workflow[21]
name:?Releaseon:push:tags:-?'v*'jobs:release:runs-on:?ubuntu-lateststeps:-?uses:?actions/checkout@v2with:fetch-depth:?0-?uses:?actions/setup-node@v2with:node-version:?'14'registry-url:?https://registry.npmjs.org/-?run:?npm?i?-g?pnpm?@antfu/ni-?run:?nci-?run:?nr?test?--if-present-?run:?npx?conventional-github-releaser?-p?angularenv:CONVENTIONAL_GITHUB_RELEASER_TOKEN:?${{secrets.GITHUB_TOKEN}}
根據每次 tags 推送,執行。
#?全局安裝?pnpm?和?ni
npm?i?-g?pnpm?@antfu/ni
#?如何存在?test?命令則執行
nr?test?--if-present
nci - clean install
nci
#?npm?ci
#?簡單說就是不更新鎖文件
#?yarn?install?--frozen-lockfile
#?pnpm?install?--frozen-lockfile
最后 npx conventional-github-releaser -p angular
conventional-github-releaser[22]
生成 changelog
。
至此我們就學習完了 install-pkg[23] 包。
7. 總結
整體代碼比較簡單。原理就是通過鎖文件自動檢測使用何種包管理器(npm、yarn、pnpm),最終用 execa[24] 執行類似如下的命令。
pnpm?install?-D?--prefer-offine?release-it?react?antd
我們學到了:
1.?如何學習調試源碼
2.?如何開發構建一個?ts?的?npm?包
3.?如何配置?github?action
4.?配置屬于自己的?eslint?預設、提升版本號等
5.?學會使用?execa?執行命令
6.?等等
還有各種依賴工具。
建議讀者克隆 我的倉庫[25] 動手實踐調試源碼學習。
最后可以持續關注我@若川。歡迎加我微信 ruochuan12 交流,參與 源碼共讀 活動,每周大家一起學習200行左右的源碼,共同進步。
參考資料
[1]
本文倉庫 https://github.com/lxchuan12/install-pkg-analysis.git,求個star^_^: https://github.com/lxchuan12/install-pkg-analysis.git
更多資料點擊閱讀原文查看
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
識別上方二維碼加我微信、拉你進源碼共讀群
今日話題
略。分享、收藏、點贊、在看我的文章就是對我最大的支持~