要全自己折腾的话,或许会陷入无尽的坑,所以我选择从偶像的 starter-ts 开始,按照自己的习惯进行一些改造。
TypeScript 自不必多说,我使用 ESLint 来检查代码风格并格式化代码,而不是使用 Prettier,想要了解更多请看 Why I don't use Prettier。如果你和 prettier 的 printWidth
也做过斗争并不能忍受的话,就会喜欢用 eslint 了,并且我们现在有了 ESLint Stylistic 这种开箱即用的配置。
Note
要配置自己的 eslint config, 可以参考偶像的 @antfu/eslint-config。
为了方便的测试我们写的库,pnpm 的 workspace 是必不可少的,可以很方便的开一个 playground。此外,它默认不提升依赖的特性也能够防止我们不小心引用了没有定义的依赖。我的 .npmrc
为:
ignore-workspace-root-check=true
public-hoist-pattern=[]
使用 bunchee 来完成打包任务,它读取 package.json 中的 exports
字段作为打包的输入输出,无需手动指定配置。
如果你希望更清楚精细的控制打包流程,可以使用 rollup 配合一些插件来自己写配置。这里有一些常用的插件推荐。
如果你想看看类似 bunchee 的其它选择,可以看看 unbuild 和 tsup
开发过程中,非必要的情况下,基本上没人想先打包再跑代码。因此,我使用 tsx 来直接执行 ts 文件,用 vitest 来测试代码。
package.json
#作为一个起手模板,它需要提前写好包的基本信息,并可以在开一个新坑的时候快速的查找替换。
基本信息处于两个位置,一个是 package.json
,一个是 README.md
,通过全局替换 pkg-placeholder
和 $description$
可以让你的包快速就位并发布。
首先你可以阅读 Ship ESM & CJS in one Package 和 Types for Submodules 这两篇文章来了解同时发布 esm 和 cjs 两种格式包相关的基础信息。
然后可以使用 publint,arethetypeswrong,modern-guide-to-packaging-js-library 这些工具来检查你的包是否符合规范。
npx publint
npx -p @arethetypeswrong/cli attw --pack .
我最终得出的配置如下:
{
"sideEffects": false,
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"*": ["./dist/*", "./dist/index.d.ts"]
}
},
"files": ["dist"]
}
使用 knip 查找项目中未使用的文件、依赖项和导出。
npx knip
使用 taze 或者 package-json-upgrade 来更新依赖。
要使我们的包版本号 +1,大抵有以下几个步骤:
如果每次都要手动做这些事情,那就太麻烦了,所以我们可以使用 release-it 来帮助我们自动化这些步骤。借助 release-it 的 hooks 功能,只在发包之前的各个阶段进行一些操作。
{
"release-it": {
"git": {
"commitMessage": "chore: release v${version}"
},
"hooks": {
"before:init": [
"pnpm run lint",
"pnpm run typecheck",
"pnpm run test --run"
]
}
}
}
我并不想将其作为依赖安装在项目中,我使用 GitHub Action 来完成 release 的操作。先看完整的配置。
name: Release
permissions:
contents: write
id-token: write
on:
workflow_dispatch:
inputs:
increment:
description: "The release type"
required: true
default: "patch"
type: choice
options:
- "major"
- "minor"
- "patch"
preRelease:
description: "The pre-release type"
required: true
default: "not"
type: choice
options:
- "alpha"
- "beta"
- "rc"
- "not"
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Git config
run: |
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
- name: Install pnpm
uses: pnpm/action-setup@v3
- name: Set node
uses: actions/setup-node@v3
with:
node-version: lts/*
- name: Login to NPM
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Setup
run: npm i -g @antfu/ni release-it changelogithub should-semantic-release
- name: Install
run: nci
- name: Pre Release
run: if should-semantic-release --verbose ; then release-it ${{ github.event.inputs.increment }} --verbose --preRelease ${{ github.event.inputs.preRelease }} && changelogithub ; fi
if: "${{ github.event.inputs.preRelease != 'not' }}"
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Release
run: if should-semantic-release --verbose ; then release-it ${{ github.event.inputs.increment }} --verbose && changelogithub ; fi
if: "${{ github.event.inputs.preRelease == 'not' }}"
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
单独使用 release-it 的话不能自动选择正确的下一个版本号,我又没找到完全符合自己想法的插件,就借助 GitHub Action 的 workflow_dispatch
条件来允许手动触发 release,传递 increment 和 preRelease 两个参数给 release-it。
使用 changelogen 可以自动生成 changelog,根据的是 commit message。
所以或许我们需要一个用来规范 commit message 的 cli,比如 cz-git 或者 cz-cli 加上 cz-conventional-changelog。
changelogen --output && prettier --write CHANGELOG.md && git add CHANGELOG.md
将 CHANGELOG.md 添加到 git 中,在下一步中将会被一起 commit。
使用 bumpp 来更新版本号,通过 cli 可以方便的选择下一个升级的版本号,bumpp 会自动更新 package.json 中的 version,然后完成 commit,tag,push 一条龙。
bumpp --all --execute \"pnpm changelog\" && npm publish
为了将上一步生成的 CHANGELOG.md 一同提交,需要使用 --all
参数。
通过 --execute
参数可以在 commit 之前执行一些命令,这里自然就是生成 changelog 了。
对于小型项目来说,我们不需要通过 GitHub Action 来编译打包,直接在本地 npm publish
即可。
为了保证我们每次 commit 的代码都没有弄坏什么事情,我使用 simple-git-hooks 来在 commit 之前进行检查。
{
"simple-git-hooks": {
"pre-commit": "pnpm check"
},
"scripts": {
"prepare": "simple-git-hooks",
"check": "pnpm lint && pnpm typecheck && pnpm build",
"prepublishOnly": "pnpm check"
}
}