with one click
create-component
// 为 SD Design Vue 组件库新增或重构组件的完整工作流。只要用户提到“新增组件”“补一个组件”“给组件库加文档/测试/样式”“按现有规范实现一个 web-vue 组件”“补齐组件导出、单测、demo、文档”“把内部组件整理成正式组件”就应触发,即使用户只显式提到其中一部分。必须覆盖源码、样式 token、导出入口、测试、文档页和验证步骤,而不是只写单个 .vue 文件或只改一个局部文件。
// 为 SD Design Vue 组件库新增或重构组件的完整工作流。只要用户提到“新增组件”“补一个组件”“给组件库加文档/测试/样式”“按现有规范实现一个 web-vue 组件”“补齐组件导出、单测、demo、文档”“把内部组件整理成正式组件”就应触发,即使用户只显式提到其中一部分。必须覆盖源码、样式 token、导出入口、测试、文档页和验证步骤,而不是只写单个 .vue 文件或只改一个局部文件。
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | create-component |
| description | 为 SD Design Vue 组件库新增或重构组件的完整工作流。只要用户提到“新增组件”“补一个组件”“给组件库加文档/测试/样式”“按现有规范实现一个 web-vue 组件”“补齐组件导出、单测、demo、文档”“把内部组件整理成正式组件”就应触发,即使用户只显式提到其中一部分。必须覆盖源码、样式 token、导出入口、测试、文档页和验证步骤,而不是只写单个 .vue 文件或只改一个局部文件。 |
这个 skill 用于在当前仓库里为组件库实现一个“可以合并”的组件,而不是只生成一个演示性质的 Vue 文件。
目标包和目录是固定的:
packages/web-vue/components/<component-name>/packages/sd-vue-docs/src/content/docs/components/<component-name>/index.mdxsrc/components/generated/ 默认先视为生成目录,但必须先核实它在当前仓库里是否真的由脚本生成、是否受版本控制、是否实际作为 demo 测试输入在这个仓库里,组件实现风格优先服从现有组件库约定,而不是通用 Vue 最佳实践的默认答案。
目标不是“能跑”,而是“达到组件库可合并、可维护、可发布的基线”。
只要进入这个 skill,默认同时记住下面几点:
<component-name>.vue 文件。index.ts、样式入口、总导出入口、测试、文档页。packages/sd-vue-docs/src/content/docs/components/index.mdx 和 packages/sd-vue-docs/src/generated/docs-sidebar.ts 是否需要同步。packages/sd-vue-docs/src/components/generated/ 这类目录,除非已经确认它在当前任务里就是人工维护源,或者当前仓库根本不存在对应的 demo 生成脚本而测试又直接消费这些 .vue 文件。DemoBlock 预览里的第一轮交互也有可见效果。*Source 变量默认应直接使用对应 demo 文件的 .vue?raw 导入,不要在 MDX 里再手写一份重复源码字符串。vendor 文件夹默认视为“外部依赖的本地化产物”,里面的内容仅供参考,不要默认它们在当前任务里就是需要维护的输入或输出。要实现的是把它们的能力内化到组件库源码里,而不是给组件库加外部运行时依赖。执行结束前,至少自查一次:源码、样式、导出、测试、文档、验证 6 个面是否都已覆盖。
下面这些行为默认禁止:
默认把任务分成两个层级推进:
这部分必须完成:
这部分在时间和上下文允许时追加,但不要先做它们、后漏掉基线:
先完成基线,再做优化。
用户出现下面这些意图时使用本 skill:
@sdata/web-vue如果用户只是改一个很小的 bug,不要强行跑完整建组件流程;只吸收其中相关章节。
编码前先确认这些信息;如果用户没给全,优先从相邻组件和仓库结构补足,实在缺失再提问:
如果用户描述非常短,优先自行从仓库推断,而不是立刻反问。只有这些信息会直接改变实现形态时再提问:
命名约定:
alert、date-pickerAlertgetPrefixCls('<name>') 生成,例如 sd-alert如果组件名称天然包含多个词,优先保持与现有目录风格一致,不要自行切换大小写策略。
在正式编码前,至少核实下面 8 个事实,而不是凭经验假设:
defineComponent 还是 <script setup>。components/index.ts 的导出写法。components/sd-vue.ts 的注册写法。__test__/index.test.ts 的断言风格。__test__/demo.test.ts 是否接统一 demo 测试脚本。components/components.ts 这类全局组件类型声明文件需要同步。components/index.scss 这类根样式聚合入口需要同步。@import url('./foo/style/index.scss'); 写法应视为有效约定,不要擅自去掉 url() 或改写路径分隔符。packages/sd-vue-docs/src/content/docs/components/index.mdx 和 packages/sd-vue-docs/src/generated/docs-sidebar.ts。如果终端历史、缓存文件、生成目录和 package.json 脚本信息互相冲突,以源码中的当前事实为准,优先级通常是:
package.json / 脚本源码开始写代码前,先把组件归到下面一种形态,再选参考实现。
适用于 Alert、Badge、Empty 这种一个主导出即可完成主要能力的组件。
要求:
适用于 Dropdown + Doption、Button + ButtonGroup、Anchor + AnchorLink 这类多导出组件。
额外要求:
components/index.ts 中的多导出components/sd-vue.ts 中的多注册适用于 Progress、DatePicker 这类同目录下存在多个展示形态或变体组件的场景。
额外要求:
适用于像 Message、Notification、Drawer.open() 这种除了组件本体,还可能有静态方法或函数式调用的能力。
额外要求:
开始实现前,至少快速对照一个现有组件。优先找一个复杂度接近的组件,确认这些点:
packages/web-vue/components/<name>/<name>.vue 的组织方式index.ts 的安装导出模式style/index.scss、style/token.scss、style/index.ts 的拆分方式__test__/index.test.ts 和 __test__/demo.test.ts 的测试粒度packages/sd-vue-docs/src/content/docs/components/<name>/index.mdx 的文档结构packages/web-vue/components/index.ts 和 packages/web-vue/components/sd-vue.ts 的总入口同步方式packages/web-vue/components/components.ts 是否还需要同步全局组件声明packages/web-vue/components/index.scss 是否还需要同步根样式入口,以及它当前的 import 写法packages/sd-vue-docs/src/content/docs/components/index.mdx 和 packages/sd-vue-docs/src/generated/docs-sidebar.ts 是否还需要同步组件发现入口参考选择建议:
alert、empty、badge 这类目录干净的组件anchor、button、dropdownprogress、date-pickerdrawer、message、notification如果组件类型判断不准,先看导出入口和 docs 页面,不要只看 .vue 文件数量。
参考时重点提取的是“结构规则”和“公共约定”,不是视觉细节或演示文案。
默认按这个结构创建:
packages/web-vue/components/<component-name>/
├── <component-name>.vue
├── index.ts
├── __test__/
│ ├── index.test.ts
│ └── demo.test.ts
└── style/
├── index.scss
├── index.ts
└── token.scss
说明:
__test__/__snapshots__/ 是测试生成产物,通常不手建.vue 文件,例如 progress/circle.vue、progress/line.vue,但仍要保留一个清晰的主入口和统一测试策略路径:packages/web-vue/components/<component-name>/<component-name>.vue
在这个仓库里,优先遵循现有组件库风格:
defineComponent<script lang="ts">,除非该模块周边明确已经统一到 <script setup>getPrefixCls('<component-name>') 生成样式前缀computed(() => [...])@zh / @en 风格_ 前缀,避免触发仓库的 oxlint no-unused-vars实现时至少覆盖这些设计面:
API 设计时还要额外检查:
modelValue、defaultValue、visible、status、size如果组件要接收复杂对象、数组或 render 逻辑,优先先看相邻复杂组件的建模方式,不要临时发明一套新约定。
如果组件是纯展示组件,避免无意义的响应式状态。
如果组件需要复杂逻辑,拆出内部工具或 hooks,但不要把公共 API 藏进难追踪的私有抽象。
实现时优先做到“相邻组件可读性一致”,而不是把文件写成抽象程度过高的范式样板。
路径:packages/web-vue/components/<component-name>/index.ts
保持现有模式:
_ComponentObject.assign 包装 installinstall 中调用 setGlobalConfig(app, options)getComponentPrefix(options) 注册组件InstanceType<typeof _Component> 作为实例类型参考结构:
import type { App } from 'vue';
import type { SDOptions } from '../_utils/types';
import { setGlobalConfig, getComponentPrefix } from '../_utils/global-config';
import _Component from './component.vue';
const Component = Object.assign(_Component, {
install: (app: App, options?: SDOptions) => {
setGlobalConfig(app, options);
const componentPrefix = getComponentPrefix(options);
app.component(componentPrefix + _Component.name, _Component);
},
});
export type ComponentInstance = InstanceType<typeof _Component>;
export default Component;
如果组件组有多个导出,确保:
路径:packages/web-vue/components/<component-name>/style/token.scss
职责:
../../style/theme/index.scss 引入基础设计 token要求:
index.scss@alert-color-close-icon@xxx-color-1 这类无法读懂的名字路径:packages/web-vue/components/<component-name>/style/index.scss
职责:
@import url('./token.scss');@{prefix}-<component-name> 形成最终类名要求:
路径:packages/web-vue/components/<component-name>/style/index.ts
固定模式:
import '../../style/index.scss';
import './index.scss';
不要省略全局样式入口,否则文档站和运行时可能出现样式缺失或优先级异常。
新增或重构组件时,至少过一遍下面的 API 审核:
string | any如果组件是对标仓库里已有同类组件,优先维持横向一致,不要为了“更优雅”擅自做一套新 API。
新增公共组件后,至少同步下面两个入口。
路径:packages/web-vue/components/index.ts
需要增加:
export { default as Alert } from './alert';export type { AlertInstance } from './alert';路径:packages/web-vue/components/sd-vue.ts
需要增加:
components 集合注册如果漏掉这一步,组件可能能单独 import,但无法通过插件全量注册使用。
如果任务是重构现有组件,也要反查这两个总入口是否已经存在陈旧导出、重复导出或类型遗漏。
路径:packages/web-vue/components/components.ts
在当前仓库里,这个文件是手工维护的全局组件类型声明入口。新增公共组件后,通常还需要补:
declare module 'vue' 中的 Sd<ComponentName> 映射如果漏掉这一步,运行时可能可用,但 Volar / TS 的全局组件类型会缺失。
路径:packages/web-vue/components/index.scss
在当前仓库里,这个文件也是手工维护入口。新增公共组件样式后,通常还需要补:
@import url('./<component-name>/style/index.scss');额外约束:
@import url('./...');,就继续沿用,不要把它改成别的形式组件至少补两类测试:行为测试和 demo 快照测试。
如果是组件组或函数式 API,再额外补一类“组合调用”测试,避免只验证静态渲染。
测试质量要求:
路径:packages/web-vue/components/<component-name>/__test__/index.test.ts
优先覆盖:
写法约定:
@vue/test-utils 的 mount建议至少有这些 case:
有下面这些情况时,应再加测试:
路径:packages/web-vue/components/<component-name>/__test__/demo.test.ts
固定模式通常是:
import demoTest from '../../../scripts/demo-test';
demoTest('<component-name>');
作用:
注意:
__snapshots__ 由测试生成,不要手写如果 demo 组件来源不明,先查 scripts/demo-test 和 docs 目录引用链路,再决定是否需要额外同步步骤。
文档页路径固定:
packages/sd-vue-docs/src/content/docs/components/<component-name>/index.mdx文档页通常包括:
title、descriptionDemoBlock 引入推荐结构:
---
title: 组件名 EnglishName
description: 一句话描述组件用途。
---
import DemoBlock from '../../../../components/docs/DemoBlock.astro';
import XxxBasicDemo from '../../../../components/generated/<component-name>/basic.vue';
export const xxxBasicSource = '...';
### 基本用法
一句话说明。
<DemoBlock source={xxxBasicSource} mainFile="src/<component-name>-basic.vue">
<XxxBasicDemo client:only="vue" />
</DemoBlock>
## API
文档编写要求:
after-close如果组件是组件组或复合组件,文档页还要补:
如果是服务式能力,还要补:
下面这个目录通常是生成产物,不要直接手改:
packages/sd-vue-docs/src/components/generated/在当前仓库里,先把这件事当成“待确认事实”,不要默认存在某条 demo 生成命令。
处理顺序:
package.json 的 scripts。如果没有确认出生成链路,优先维护最终 MDX 页面和可执行测试,不要把未知生成流程写成硬要求。
当前仓库还要额外注意:
package.json 里不存在 docs:generate-demos 或 generate-demos 一类脚本,就不要因为终端历史里出现过类似命令而把它当真scripts/demo-test 直接从 packages/sd-vue-docs/src/components/generated/<component-name>/*.vue 加载 demo,而这些文件又已经受版本控制,那么它们在当前仓库里应视为需要维护的输入文件,而不是可以忽略的纯产物docs:prepare、docs:vendor、docs:vendor:only、dev、dev:serve、build、build:site、previewDemoEditor 能运行不等于 DemoBlock 预览可用;如果组件有 tooltip / popover / teleported popup / overflow 裁剪 / 懒激活切换,必须按文档预览容器的真实约束检查一遍demo 不是越多越好,优先覆盖使用者最关心的能力。默认至少包含:
复杂组件再补:
避免这些低价值 demo:
按这个顺序推进,避免返工:
<component-name>.vue 或相关变体组件。index.ts 安装导出。style/token.scss、style/index.scss、style/index.ts。packages/web-vue/components/index.ts。packages/web-vue/components/sd-vue.ts。packages/web-vue/components/components.ts。packages/web-vue/components/index.scss。__test__/index.test.ts。__test__/demo.test.ts。packages/sd-vue-docs/src/content/docs/components/<component-name>/index.mdx。packages/sd-vue-docs/src/content/docs/components/index.mdx 和 packages/sd-vue-docs/src/generated/docs-sidebar.ts,确保组件在文档导航中可发现。generated/<component-name> 是否需要补 demo 源文件。DemoBlock 预览里的第一轮交互不是“无效果”。不要跳过第 1 步和第 3 步。很多返工都来自先写实现、后发现组件形态判断错了。
如果是重构现有组件,开始改之前先补一件事:
优先使用仓库中已经验证存在的命令:
pnpm --filter @sdata/web-vue test
pnpm --filter @sdata/web-vue run build:module
pnpm --filter @sd-design/sd-vue-docs run docs:vendor
pnpm --filter @sd-design/sd-vue-docs run build
pnpm --filter @sd-design/sd-vue-docs run dev
验证目标:
如果只需要快速验证,也至少跑组件测试;如果改了文档或样式入口,补跑 docs 相关命令。
更严格的验证顺序建议:
@sdata/web-vue 级别测试如果某条验证因为仓库基线问题失败,要区分:
不要把仓库历史遗留问题误写成当前改动失败。
如果用户要求的是“正式组件”而不是临时骨架,结束前再检查这些项:
如果任务触及现有 public API,默认把兼容性风险写进最终说明。
只有同时满足下面条件,才算组件真正完成:
DemoBlock 预览已验证,不存在“在线编辑器可用但文档示例首轮交互无效果”的断层更严格地说,只有当下面三个问题都能回答“是”时,才算真正完成:
有任一答案是否定,都不应把任务表述成“完全完成”。
<component-name>.vue,忘了 index.tspackages/web-vue/components/index.ts,忘了 packages/web-vue/components/sd-vue.tspackages/web-vue/components/components.ts 的全局组件类型声明packages/web-vue/components/index.scss 的根样式入口style/index.tsindex.scss 堆满魔法值demo.test.ts如果出现这些反模式,优先回退到和相邻成熟组件一致的简单方案。
在基线已经完成的前提下,可以继续检查这些优化点:
执行这个 skill 时,最终输出至少要告诉用户:
如果有兼容性影响,再加第 4 项:
推荐直接按这个收尾模板输出:
已完成:
- ...
已验证:
- ...
剩余风险:
- ...
如果用户是让你“先搭骨架”,也要明确说明哪些文件已经建好,哪些内容只是占位,避免让用户误以为组件已可发布。
如果用户要的是“最终可合并版本”,不要用“已完成骨架”这种表述模糊交付状态。