手把手教你如何实现开源项目的打包构建、版本发布以及贡献指南(终结篇)

作者:易师傅github

声明:本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

前言

说在前头:开源的魅力在于它的开放性、协作性和共享精神,无论你是新手小白,还是经验丰富的老油条,都能在开源的世界里找到属于自己的舞台。

在前面咱们已经梳理完了实现无头组件库的大部分核心功能,接下来也是一些收尾工作了,从零开始,系统地掌握开源项目的打包构建、版本发布及贡献指南的制定技巧

大家也可系统性的查看这篇专栏《Headless UI 无头组件库的介绍与实现》中前面所讲的文章,这样才能融会贯通。

一、打包构建

其实在之前的文章中简要的讲解了打包构建,但是讲的比较浅显,接下来我们详细的介绍一下相关功能与实现。

打包工具选择

  • Vue CLI:可以用来打包Vue组件库为各种格式,包括UMD、CommonJS、ES模块等
  • Vite:一个由Vue作者尤雨溪开发的现代前端构建工具,特别适合开发和打包Vue组件库。
  • Webpack:不解释了
  • Rollup:流行的打包工具,适合打包工具库,因为它擅长生成体积小的ES模块代码。

打包工具有很多种,这里就主要说明这几种。

以目前的开源社区来讲,其中还属 Vite 独领风骚;

所以咱们还主要以 Vite 来讲解。

介绍核心库 packages/vue 的打包功能

1.packages/vue子包配置脚本:

json 复制代码
"scripts": {
    "build": "vue-tsc && vite build",
},

2.命令介绍:

vue-tsc:理解 Vue 单文件组件(SFC,即 .vue 文件)中的 <script> 标签内的 TypeScript 代码,并对这些代码进行类型检查。

vite build:vite 构建工具的一个命令,用于将开发环境的项目代码编译、打包成适合生产环境部署的静态资源。并且会执行 vite.config.ts 文件中的配置。

根目录配置 build

因为这是一个 monorepo 的项目,所以我们需要在根目录配置一下 build 命令

json 复制代码
"scripts": {
    "clear": "rimraf packages/**/dist",
    "build": "pnpm run clear && pnpm -r --filter=./packages/** run build",
},

rimraf:一个在 Node.js 环境中常用的 npm 包,用于递归删除文件和文件夹。

然后再运行 pnpm build 即可

二、版本发布

接下来主要介绍一下相关版本发布的步骤。

第一步:生成 changeset

运行命令:

bash 复制代码
# package.json
script: {
    "changeset": "changeset && changeset version"
}

# 运行
pnpm changeset

按照下面的步骤执行

第一:选择你更改发布的包?

第二:选择你要发布包的版本(可选大版本还是小版本)?

第三:输入你的主要更改日志?

第四:确认你的变更?

就会在你更改的那个子包下生成 CHANGELOG.md 更改文档集。

第二步:build 构建

bash 复制代码
pnpm build

第三步:发布

复制代码
changeset publish

第四步:关联 git 远程 Tag(视情况运行)

bash 复制代码
git push --follow-tags

三、 一键生成组件 cli

因为一个开源仓库不可能是只有一个人完成,同时为了更好的安排团队各自负责的组件,所以为了避免团队中工程师在开发一个新组件阶段的不规范所可能产生的问题;

咱们要先完成一个自动生成无头组件案例的 cli 脚本,这样就避免很多不必要的麻烦。

1. 新建 scripts

bash 复制代码
mkdir script

touch gen.sh

2. 编写生成代码

在研发前,我们先简要的了解下对应的需求。

简要需求流程说明:

  1. 判断是否存在了该组件
  2. 存在直接报错
  3. 未存在则生成对应的模版文件,模版包括:
    • 组件模版
    • 测试用例模版
    • 文档模版
  4. 在入口 index.ts 中追加导出

我们在了解需求后,正式进入研发阶段:

我们直接使用 shell 脚本来编写,不懂的没关系,知道其原理就行了

bash 复制代码
#! /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 1
fi

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}"
done
NAME=$NORMALIZED_NAME

DIRNAME="$FILE_PATH/src/$NAME"

# 1.判断组件是否存在
if [ -d "$DIRNAME" ]; then
  echo "$INPUT_NAME 组件已经存在, 请更换后再试"
  exit 1
fi

############## 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 <<EOF
export {
  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 <<EOF
import { 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

json 复制代码
script: {
    "gen": "bash ./scripts/gen.sh"
}

运行 pnpm gen 组件名

必须要一个组件名为参数,咱们以 Alert 组件为例:

pnpm gen alert

运行结果:

接下来你就可以畅快的编写属于你的组件啦!

四、贡献指南发布

环境要求:

  • Node.JS >= 16
  • pnpm >= 8

代码仓库地址:github.com/jeddygong/y...

Issue 规范

  • issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
  • 在提交 issue 之前,请搜索相关内容是否已被提出。
  • 请说明 @yi-ui/vueVue 的版本号,并提供操作系统和浏览器信息。
  • 可以先在本地 playground 中试运行一下 demo。

Pull Request 规范

  • 请先 fork 一份到自己的项目下,不要直接在仓库下建分支。
  • commit 信息严格遵循 git 提交规范,例如 fix(components): [scrollbar] fix xxx bug
  • 执行 npm run build 后可以正确打包文件。
  • 提交 PR 前请 rebase,确保 commit 记录的整洁。
  • 合并代码需要两名维护人员参与:一人进行 review 后 approve,另一人再次 review,通过后即可合并。

目录结构规范

项目采用 Monorepo 进行代码管理,下面展示了主要目录结构

bash 复制代码
root
├── docs                     # 文档
│   ├── components           # 组件文档
│   │   └── HoverCard.md
├── packages
│   ├── plugins              # 插件支持
│   │   ├── nuxt
│   │   └── resolver
│   ├── shared               # 工具函数库
│   │   ├── hooks
│   │   ├── utils
│   │   └── vue
│   └── vue
│       ├── src              # 组件
│       └── utils            # 工具函数
└── playground               # 本地开发调试操场
    ├── nuxt3                # nuxt3 操场
    └── vue3                 # vue3 操场

组件目录结构 (以HoverCard为例):

bash 复制代码
# packages/vue/src/HoverCard
src
└──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 分支代码

bash 复制代码
# https 
git clone https://github.com/jeddygong/yi-ui.git

# ssh
git clone git@github.com:jeddygong/yi-ui.git

新增组件:

css 复制代码
pnpm gen [组件名]

例如新增 alert 组件:运行 pnpm gen alert 即可

修改文档

bash 复制代码
pnpm run docs:dev

调试本地组件

bash 复制代码
# vue
pnpm run play:vue

# nuxt
pnpm run play:nuxt

源码编译

bash 复制代码
pnpm run build

新增组件流程:

  1. 新增组件:pnpm gen [组件名]
  2. 开始研发:coding
  3. 运行测试用例:pnpm run test
  4. 编译:pnpm run build
  5. changeset:pnpm run changeset
  6. git rebase 合并代码至对应的 develop 分支
  7. 等待 owner 审核合并代码

总结

最后,本篇文章也几乎是当前专栏无头组件库的实现的最后一篇终结文章了,后续就视情况更新一些拓展知识了,因为整个无头组件库的实现专栏涉及的知识点也基本全部讲解了。

当然其中难免会有一些细节的疏忽,望海涵,大家如若有发现,可留言,作者后续会及时更新。

后续 Headless UI 的一些拓展进阶以及 shadch/ui 也会不定时更新了。

Headless UI 往期相关文章:

  1. 在 2023 年屌爆了一整年的 shadcn/ui 用的 Headless UI 到底是何方神圣?
  2. 实战开始 🚀 在 React 和 Vue3 中使用 Headless UI 无头组件库
  3. 无头组件库既然这么火 🔥 那么我们自己手动实现一个来完成所谓的 KPI 吧
  4. 泰裤辣 🚀 原来实现一个 Popover 无头组件比传统组件简单辣么多!!
  5. 手把手教你写一个 headless 无头组件的单元测试、集成测试、E2E 测试
  6. 用更合适的文档库!打造专属品质,尽显码农风采!

如果想跟我一起讨论技术吹水摸鱼 , 欢迎加入前端学习群聊

如果想一起讨论技术:欢迎加入技术讨论群

如果想一起吹水摸鱼:欢迎加入吹水摸鱼群

如果想一起老司机吹水摸鱼:欢迎加入老司机吹水摸鱼群(懂得都懂)

如果扫码人数满了,可以扫码添加个人 vx 拉你:JeddyGong

感谢大家的支持,码字实在不易,其中如若有错误,望指出,如果您觉得文章不错,记得 点赞关注加收藏 哦 ~

关注我,带您一起搞前端 ~

相关推荐
weixin_382395239 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__9 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.9 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~10 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华11 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子13 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅13 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni14 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学15 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端