手把手教你如何实现开源项目的打包构建、版本发布以及贡献指南(终结篇)
/ 13 min read
Table of Contents
前言
说在前头:开源的魅力在于它的开放性、协作性和共享精神,无论你是新手小白,还是经验丰富的老油条,都能在开源的世界里找到属于自己的舞台。
在前面咱们已经梳理完了实现无头组件库的大部分核心功能,接下来也是一些收尾工作了,从零开始,系统地掌握开源项目的打包构建、版本发布及贡献指南的制定技巧。
大家也可系统性的查看这篇专栏《Headless UI 无头组件库的介绍与实现》中前面所讲的文章,这样才能融会贯通。
一、打包构建
其实在之前的文章中简要的讲解了打包构建,但是讲的比较浅显,接下来我们详细的介绍一下相关功能与实现。
打包工具选择
Vue CLI:可以用来打包Vue组件库为各种格式,包括UMD、CommonJS、ES模块等Vite:一个由Vue作者尤雨溪开发的现代前端构建工具,特别适合开发和打包Vue组件库。Webpack:不解释了Rollup:流行的打包工具,适合打包工具库,因为它擅长生成体积小的ES模块代码。
打包工具有很多种,这里就主要说明这几种。
以目前的开源社区来讲,其中还属 Vite 独领风骚;
所以咱们还主要以 Vite 来讲解。
介绍核心库 packages/vue 的打包功能
1.packages/vue子包配置脚本:
"scripts": { "build": "vue-tsc && vite build",},2.命令介绍:
vue-tsc:理解 Vue 单文件组件(SFC,即 .vue 文件)中的 <script> 标签内的 TypeScript 代码,并对这些代码进行类型检查。
vite build:vite 构建工具的一个命令,用于将开发环境的项目代码编译、打包成适合生产环境部署的静态资源。并且会执行 vite.config.ts 文件中的配置。
根目录配置 build
因为这是一个 monorepo 的项目,所以我们需要在根目录配置一下 build 命令
"scripts": { "clear": "rimraf packages/**/dist", "build": "pnpm run clear && pnpm -r --filter=./packages/** run build",},
rimraf:一个在 Node.js 环境中常用的 npm 包,用于递归删除文件和文件夹。
然后再运行 pnpm build 即可
二、版本发布
接下来主要介绍一下相关版本发布的步骤。
第一步:生成 changeset
运行命令:
# package.jsonscript: { "changeset": "changeset && changeset version"}
# 运行pnpm changeset按照下面的步骤执行
第一:选择你更改发布的包?
第二:选择你要发布包的版本(版本的选择一共有三种类型,分别是 patch、minor 和 major,严格遵循 semver 规范)?
第三:输入你的主要更改日志?
第四:确认你的变更?
就会在你更改的那个子包下生成 CHANGELOG.md 更改文档集。
第二步:build 构建
pnpm build第三步:发布
changeset publish第四步:关联 git 远程 Tag(视情况运行)
git push --follow-tags三、 一键生成组件 cli
因为一个开源仓库不可能是只有一个人完成,同时为了更好的安排团队各自负责的组件,所以为了避免团队中工程师在开发一个新组件阶段的不规范所可能产生的问题;
咱们要先完成一个自动生成无头组件案例的 cli 脚本,这样就避免很多不必要的麻烦。
1. 新建 scripts
mkdir script
touch gen.sh2. 编写生成代码
在研发前,我们先简要的了解下对应的需求。
简要需求流程说明:
- 判断是否存在了该组件
- 存在直接报错
- 未存在则生成对应的模版文件,模版包括:
- 组件模版
- 测试用例模版
- 文档模版
- 在入口 index.ts 中追加导出
我们在了解需求后,正式进入研发阶段:
我们直接使用 shell 脚本来编写,不懂的没关系,知道其原理就行了
#! /bin/bash
NAME=$1
FILE_PATH=$(cd "$(dirname "${BASH_SOURCE[0]}")/../packages/vue" && pwd)DOCS_PATH=$(cd "$(dirname "${BASH_SOURCE[0]}")/../docs" && pwd)
re="[[:space:]]+"
if [ "$#" -ne 1 ] || [[ $NAME =~ $re ]] || [ "$NAME" == "" ]; then echo "Usage: pnpm gen \${name} with no space" exit 1fi
INPUT_NAME=$NAME
# 转成大写驼峰NORMALIZED_NAME=""for i in $(echo $NAME | sed 's/[_|-]\([a-z]\)/\ \1/;s/^\([a-z]\)/\ \1/'); do C=$(echo "${i:0:1}" | tr "[:lower:]" "[:upper:]") NORMALIZED_NAME="$NORMALIZED_NAME${C}${i:1}"doneNAME=$NORMALIZED_NAME
DIRNAME="$FILE_PATH/src/$NAME"
# 1.判断组件是否存在if [ -d "$DIRNAME" ]; then echo "$INPUT_NAME 组件已经存在, 请更换后再试" exit 1fi
############## 2.生成核心文件模版mkdir -p "$DIRNAME"mkdir -p "$DIRNAME/__tests__"
cat > "${DIRNAME}/${NAME}.vue" <<EOF<script lang='ts' setup>// init here</script><template> <${NAME}> <slot></slot> </${NAME}></template>EOF
cat > $DIRNAME/index.ts <<EOFexport { default as ${NAME},} from './${NAME}.vue'EOF############## 2.生成核心文件
############## 3.生成测试用例模版cat > $DIRNAME/__tests__/$NAME.vue <<EOF<script setup lang="ts">import { ref } from 'vue'import { $NAME } from '@/$NAME'
</script><template> <${NAME}> <div>组件运行</div> </${NAME}></template>EOF
cat > $DIRNAME/__tests__/index.test.ts <<EOFimport { beforeEach, describe, expect, it } from 'vitest'import { mount } from '@vue/test-utils'import $NAME from './${NAME}.vue'import type { VueWrapper } from '@vue/test-utils'
describe('$NAME Component', () => { let wrapper: VueWrapper<InstanceType<typeof $NAME>> beforeEach(() => { wrapper = mount($NAME, { attachTo: document.body }) })
it('测试 $NAME 组件是否渲染成功', () => { expect(wrapper.exists()).toBe(true) })})EOF############## 3.生成测试用例
############## 4.生成文档模版
cat > $DOCS_PATH/components/$INPUT_NAME.md <<EOF---title: $NAME---
# $NAME
## 基础用法EOF
############## 4.生成文档模版
############## 5.在入口 index.ts 中追加导出echo "export * from './$NAME'" >> $FILE_PATH/src/index.ts############## 5.在入口 index.ts 中追加导出3. 新增生成命令&运行
编辑 package.json
script: { "gen": "bash ./scripts/gen.sh"}运行 pnpm gen [组件名]
必须要一个组件名为参数,咱们以 Alert 组件为例:
pnpm gen alert
运行结果:
接下来你就可以畅快的编写属于你的组件啦!
四、贡献指南发布
环境要求:
- Node.JS >= 16
- pnpm >= 8
代码仓库地址:https://github.com/jeddygong/yi-ui
Issue 规范
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
- 在提交 issue 之前,请搜索相关内容是否已被提出。
- 请说明
@yi-ui/vue和Vue的版本号,并提供操作系统和浏览器信息。 - 可以先在本地
playground中试运行一下 demo。
Pull Request 规范
- 请先 fork 一份到自己的项目下,不要直接在仓库下建分支。
- commit 信息严格遵循 git 提交规范,例如
fix(components): [scrollbar] fix xxx bug。 - 执行
npm run build后可以正确打包文件。 - 提交 PR 前请 rebase,确保 commit 记录的整洁。
- 合并代码需要两名维护人员参与:一人进行 review 后 approve,另一人再次 review,通过后即可合并。
目录结构规范
项目采用 Monorepo 进行代码管理,下面展示了主要目录结构
root├── docs # 文档│ ├── components # 组件文档│ │ └── HoverCard.md├── packages│ ├── plugins # 插件支持│ │ ├── nuxt│ │ └── resolver│ ├── shared # 工具函数库│ │ ├── hooks│ │ ├── utils│ │ └── vue│ └── vue│ ├── src # 组件│ └── utils # 工具函数└── playground # 本地开发调试操场 ├── nuxt3 # nuxt3 操场 └── vue3 # vue3 操场组件目录结构 (以HoverCard为例):
# packages/vue/src/HoverCardsrc└──button ├── __tests__ # 单元测试 │ ├── HoverCard.vue # 组件测试 │ └── index.test.ts ├── HoverCardRoot.vue # 根组件 ├── HoverCardContent.vue # 组件内容 ├── HoverCardContentImpl.vue # 组件内容模版 ├── HoverCardPortal.vue # 组件入口 ├── HoverCardTrigger.vue # 组件触发事件 ├── HoverCardArrow.vue # 组件箭头 ├── index.ts # 组件入口 └── utils.ts # 工具函数研发说明
clone develop 分支代码
# httpsgit clone https://github.com/jeddygong/yi-ui.git
# ssh新增组件:
pnpm gen [组件名]例如新增 alert 组件:运行 pnpm gen alert 即可
修改文档
pnpm run docs:dev调试本地组件
# vuepnpm run play:vue
# nuxtpnpm run play:nuxt源码编译
pnpm run build新增组件流程:
- 新增组件:
pnpm gen [组件名] - 开始研发:
coding - 运行测试用例:
pnpm run test - 编译:
pnpm run build - changeset:
pnpm run changeset - git rebase 合并代码至对应的 develop 分支
- 等待 owner 审核合并代码
总结
最后,本篇文章也几乎是当前专栏无头组件库的实现的最后一篇终结文章了,后续就视情况更新一些拓展知识了,因为整个无头组件库的实现专栏涉及的知识点也基本全部讲解了。
当然其中难免会有一些细节的疏忽,望海涵,大家如若有发现,可留言,作者后续会及时更新。
后续 Headless UI 的一些拓展进阶以及 shadch/ui 也会不定时更新了。
Headless UI 往期相关文章:
- 在 2023 年屌爆了一整年的 shadcn/ui 用的 Headless UI 到底是何方神圣?
- 实战开始 🚀 在 React 和 Vue3 中使用 Headless UI 无头组件库
- 无头组件库既然这么火 🔥 那么我们自己手动实现一个来完成所谓的 KPI 吧
- 泰裤辣 🚀 原来实现一个 Popover 无头组件比传统组件简单辣么多!!
- 手把手教你写一个 headless 无头组件的单元测试、集成测试、E2E 测试
- 用更合适的文档库!打造专属品质,尽显码农风采!
如果想跟我一起讨论技术吹水摸鱼, 欢迎加入前端学习群聊
如果想一起讨论技术:欢迎加入技术讨论群
如果想一起吹水摸鱼:欢迎加入吹水摸鱼群
如果想一起老司机吹水摸鱼:欢迎加入老司机吹水摸鱼群(懂得都懂)
如果扫码人数满了,可以扫码添加个人 vx 拉你:JeddyGong
感谢大家的支持,码字实在不易,其中如若有错误,望指出,如果您觉得文章不错,记得 点赞关注加收藏 哦 ~