links:

初始化仓库

首先在 Github 上创建好仓库 ,定义好开源协议、README、和 .gitignore等文件, 然后 clone 下来,并使用 npm init 初始化。

配置 TypeScript

pnpm add typescript tsup -D

安装好之后通过 tsc init 生成 tsconfig.json 文件,并根据具体情况设置配置项。

tsup 是一个用来快速开发和打包 TypeScript库的工具,由 esbuild 提供支持,可以将 TypeScript 代码编译成 CommonJsESM 等,支持 js、ts、json、mjs、tsx 格式,实验性支持 css

tsup 有两种配置方式,一种是直接使用 cli,一种是使用单独的配置文件 ts.config,这里我使用的是 cli 的形式,具体使用方法看文档,安装好之后在 package.json
文件中添加命令

"build": "tsup src/index.ts --format cjs,esm --dts",

参数的意思是将入口文件 src/index.ts 打包成 cjsesm格式,并生成 .d.ts类型文件,默认输出目录为 dist。tsup 支持 --watch--onSuccess 参数,分别为监听文件修改和成功后的回调。

另外 package.json 中需要配置我们的入口文件

"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",

配置 ESlint 和 Prettierc

具体的ESLint配置过程不写,根据具体情况来配置,这里直接贴代码。

Eslint

再 package.json 文件中添加命令

"lint": "eslint",
const globals = require('globals');
const parser = require.resolve('@typescript-eslint/parser');
const parserInstance = require(parser);
const eslintPluginPrettier = require.resolve('eslint-plugin-prettier');
const pluginPrettier = require(eslintPluginPrettier);
const eslintConfigPrettier = require.resolve('eslint-config-prettier');
const configPrettier = require(eslintConfigPrettier);
 
module.exports = [
{
	files: ['**/*.ts', '**/*.js'],
	ignores: ['**/dist/**', '**/node_modules/**'],
	languageOptions: {
	parser: parserInstance,
	globals: {
	...globals.commonjs,
	...globals.browser,
	...globals.es2021,
	...globals.node
	}
},
plugins: {
	prettier: pluginPrettier
},
rules: {
	...configPrettier.rules,
	...pluginPrettier.configs.recommended.rules,
	// prettier
	'prettier/prettier': [
	'warn',
	// LF and CRLF
	{
			endOfLine: 'auto'
		}
	],
		semi: 'error',
			'no-unused-vars': 'warn',
			'prefer-const': 'error'
		}
	}
];

prettier

{
	"printWidth": 80,
	"tabWidth": 2,
	"useTabs": false,
	"singleQuote": true,
	"semi": true,
	"trailingComma": "none",
	"bracketSpacing": true
}
// .prettierignore
dist
node_modules
pnpm-lock.yaml

配置Vitest测试工具

pnpm add vitest -D

在文件目录中新建index.test.ts,并添加以下测试 demo

import { describe, expect, it } from 'vitest';
 
describe('Whatever', () => {
	it('should pass CI', () => {
		expect(1).toBe(1);
	});
});

package.json 中添加 script

"dev": "vitest",
"test": "vitest run",

这里使用 vitest 来实现我们的 dev 命令,主要是因为现在开发的这个库是一个独立的库,不需要在项目中自己运行,我们直接根据测试来验证我们的代码逻辑是否正确,直接执行 vitest 命令会进入监听模式,只要我们的 .test.ts 文件发生了变动,就会重新运行我们的测试用例,我们只需要根据测试用来在验证我们的代码就可以了,既方便又准确。

Github Actions

main.yml

使用 Github Actions 功能来实现我们仓库的自动化,例如每次提交后自动运行ci 打包,判断是否有问题,自动发布等等。首先在目录下新建 .github/workflows文件夹,然后新建 main.yaml 文件并添加以下代码

name: CI
on:
  push:
    branches:
      - "**"
  pull_request:
    branches:
      - "**"
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 7
      - uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: "pnpm"
 
      - run: pnpm install --frozen-lockfile
      - run: pnpm run ci

然后在 package.json 中添加 ci 命令:

"ci": "pnpm run lint && pnpm run test && pnpm run build"

上传当前文件到 Github 之后就可以在 GitHub 的 Actions 下看到对应的自动流程了
CleanShot 2023-02-24 at 02.43.57@2x.png

publish.yml

添加 publish.yml 文件,用于我们的自动化发布流程,只需要点击按钮就会将包发布/更新到 npm 上

name: Publish
on:
  push:
    branches:
      - "main"
 
concurrency: ${{ github.workflow }}-${{ github.ref }}
 
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 7
      - uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: "pnpm"
 
      - run: pnpm install --frozen-lockfile
      - name: Create Release Pull Request or Publish
        id: changesets
        uses: changesets/action@v1
        with:
          publish: pnpm run release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
 
  • name
    • Create Release Pull Request or Publish
      • 创建一个 Publish PR,当我们执行该流程时,会自动创建一个用于发布的 PR,通过之后就可以进行发布
    • publish
      • 流程执行时会执行 pnpm run release 命令
    • env
      • NPM_TOKEN npm 的用于 Publish 的 token,在下面会配置

release

需要在 package.json 中添加 release 命令用于我们的 Publish Action 的执行

"release": "pnpm run lint && pnpm run test && pnpm run build && changeset publish"

配置 Npm Token

我们通过将 Npm Token 链接到 GIthub 项目的方式来实现我们的自动化发布,首先登录 Npm 创建一个 Token
CleanShot 2023-02-24 at 02.45.55@2x.png
CleanShot 2023-02-24 at 02.46.29@2x.png

需要选择 Publish 选项,并且生成成功后一定要将 token 复制到其他地方,因为 token 只会在生成成功的时候显示一次,后面就再也看不到具体的 token 了
CleanShot 2023-02-24 at 02.46.51@2x.png

复制刚才生成的 token 并打开我们的 Github 仓库的设置页添加 Token,token 的名称需要设置为 NPM_TOKEN,值为我们刚才在 Npm 生成的值
CleanShot 2023-02-24 at 02.48.30@2x.png

@changesets/cli

简单来说 Changesets 就是生成 changelog的工具,适用于管理版本及变更日志的工具,专注于多包管理。

  1. 安装: pnpm add @changeset/cli -D
  2. 初始化 pnpm changeset init 在项目根目录下生成 .changeset 目录

当前库做了修改之后执行 pnpm changeset 或者 pnpm changeset add 来生成 changeset 文件
CleanShot 2023-02-25 at 02.56.10@2x.png
.changeset/fair-peas-whisper.md 文件中包含了包信息、版本信息、CHANGELOG 信息,如果对当前 CHANGELOG 信息不满意,还可以直接修改,当 Publish Action 执行 pnpm run release 的时候,会同时执行 changeset publish 消耗掉当前文件。完成后将代码提交到 Github 上,会自动触发 Publish Action.

Workflow Publish Action

注意,因为我们的 Publish Action 需要使用到 GITHUB_TOKEN,默认的新仓库 Workflow 是没有适当的权限的

如果Action 遇到了 The process '/usr/bin/git' failed with exit code 128 的错误
CleanShot 2023-02-25 at 03.15.45@2x.png
需要设置 workflow 使用 GITHUB_TOKEN的权限,在仓库的 Setting Actions General 下设置 Workflow Permissions,勾选 Read and write permissions 选项 。如果 Action 需要创建 pull requests,则需要将最后的 Allow Github Actions to create and approve pull request 选项也勾选上,否则会报
GitHub Actions is not permitted to create or approve pull requests. 错误

如果是组织项目,则需要在组织的设置中去设置

CleanShot 2023-02-25 at 03.22.38@2x.png

保存后重新执行失败的Publish Action,如果一切没问题,就会在看到的仓库的 Pull requests 下有了新的 PR:Version Packages,确认合并当前 PR,会自动运行 Action。运行成功后不出意外就会发布到 Npm 上。
但是,如果是新的仓库,大概率会运行失败,如果出现了下面的错误,则还是权限的错误

Error: The process '/home/runner/setup-pnpm/node_modules/.bin/pnpm' failed with exit code 1

需要检查 package.json.changeset/config.json下的配置,package.json下需要配置

"private": false

private 属性是 npm 为了防止意外发布私有存储库的方法,如果设置了 “private”: true, npm 将拒绝发布它。

.changeset/config.json下配置

"access": "public"

changesetaccess 属性同样是一种为了防止将私有包发布到 npm 的方法,默认情况下 changeset 创建的配置文件中 access值为restricted,需要手动修改为public。修改后重新 push 代码

npm 2FA 密码导致的错误

github action This operation requires a one-time password from your authenticator

如果重新 Publish 的过程中遇到了上面的错误,则是因为 Npm 开启了 2FA 验证导致的,目前我的解决方法是关闭写入权限使用 2FA,但是这样肯定是不推荐和不安全的,但是暂时还没找到好的解决方案,等后面有空了查下相关资料
CleanShot 2023-02-25 at 03.59.49@2x.png

可以在发布完成后取消上面的勾选,然后再去npm 包的设置页面单独关闭当前包的 发布权限

如果一切没有问题,现在就可以在 npm 上看到我们发布的包了。自此,我们包的第一个版本发布完毕 🤡

.npmignore

添加 .npmignore 文件,将不必要的文件不上传到 npm

.changeset
src
scripts
pnpm-lock.yaml
tsconfig.json
eslint.config.js
.editorconfig
.prettierignore
.prettierrc
.gitignore
.github
.changeset
example
test
 

Npm 包版本号规范以及更新策略

使用 Semver 版本号规则,详见:Semantic Versioning 2.0.0 | Semantic Versioning
版本号检测工具:semver - npm

  • major 主版本号:当做了不兼容的 API 修改,大版本修改
  • minor 次版本号:当做了向下兼容的功能性洗澡能,可以理解为 Feature 版本
  • patch:修订版本:当做了向下兼容的问题修正,可以理解为 Bug fix 版本

版本号规则:

  • 1.2.2-0
  • {major}.{minor}.{patch}.{pre-release}
  • 主版本号.次版本号.修订版本号.非正式版版本号

版本号标签

  • latest:默认
  • alpha:内测
  • beta:公测
  • next:下一个
  • rc:候选
  • experimental:实验

pnpm-lock.yaml 更新后运行失败

CleanShot 2023-03-08 at 00.21.43@2x.png

Lockfile is up to date, resolution step is skipped

ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with package.json
variable/actions/runs/4295423882/jobs/7485816290#step:5:10)Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"

原因是在 CI 环境中, frozen-lockfile 默认是开启的,所以在 Github Workflow 流程中,如果依赖发生了变更,需要执行

pnpm install --no-frozen-lockfile

然后运行 pnpm changeset 并提交更新 lockfile 文件之后再运行