关于 experience-ui-bundle-frontend-generate
用于修改基于 React 和 TypeScript 构建的现有 Salesforce UI bundle。它要求先定位 bundle 并检查脚手架状态,再指导页面、布局、组件和响应式界面开发。
主要功能
- 01定位已配置的 bundle 目录
- 02编辑前检查脚手架条件
- 03指导页面、页眉和组件开发
- 04遵循 React 与 TypeScript 规范
- 05要求布局适配移动设备
适用场景
- 01为已有脚手架的 UI bundle 添加页面
- 02更新导航或应用品牌信息
- 03构建响应式 UI 组件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill experience-ui-bundle-frontend-generate安装后在 Claude Code 中输入/experience-ui-bundle-frontend-generate确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/component.mdheader-footer.mdpage.mdscripts/check-preconditions.mjsresolve-ui-bundle.mjsverify-rules.mjs详细介绍
UI Bundle UI
确定 Bundle 目录
应用以下任一规则或写入任何文件之前,必须先运行 node scripts/resolve-ui-bundle.mjs [project-root]——临时执行 find/ls 不能替代此步骤;它不会执行下文的退出码检查。始终通过 node 调用(不要直接运行可执行文件),以确保在 Windows、macOS 和 Linux 上都能正常工作。该脚本会读取 sfdx-project.json 中的 packageDirectories[0].path(不会假设路径为 force-app——源路径可配置),并在 <sourceDir>/main/default/uiBundles/ 下查找:
- 退出码 0,Bundle 路径打印到标准输出:找到且只找到一个 Bundle 目录——该目录就是 Bundle 目录。使用准确的目录名称;绝不要用其他名称替代(例如提示模板中的通用示例 "AcmePortal"),必须使用实际打印出的名称。
- 退出码 2,候选项打印到标准错误:存在多个
uiBundles/*子目录——不要猜测,也不要写入其中任何目录,或写入打印列表中没有的 Bundle 名称。在编辑或运行任何命令之前,先询问用户要使用哪个应用/Bundle。 - 退出码 1:
sfdx-project.json缺失或无效,或者完全没有找到 Bundle 目录。
所有 npm/lint/build/dev 命令都必须在解析出的 Bundle 目录内运行,绝不能从项目根目录运行。
前置条件
应用以下任何规则之前,确认这是一个已存在且已搭建的 UI Bundle:必须运行 node scripts/check-preconditions.mjs <bundle-dir>,并使用 resolve-ui-bundle.mjs 打印出的目录。
- 单 Bundle(退出码 0)情形:在该 Bundle 上运行一次。
- 多 Bundle(退出码 2)情形:暂时不要运行——先按照上文“确定 Bundle 目录”中的说明,询问用户要使用哪个应用/Bundle。用户指定后,仅针对该 Bundle 运行
check-preconditions.mjs。绝不要在用户选定之前,试探性地对多个候选项运行该脚本——这会触及/检查用户未要求处理的 Bundle。 - 退出码 0:该 Bundle 包含
src/appLayout.tsx、src/routes.tsx和src/components/ui/——继续操作。 - 退出码 1,并列出了缺失项:这是一个全新的 SFDX 项目、非 UI Bundle 的 React 项目,或仅部分搭建的 Bundle——停止。不要退而使用通用 React 知识(例如
react-router-dom、硬编码的 basename 或原始 HTML),也不要手写appLayout.tsx/routes.tsx/页面/组件来“补齐”缺失的脚手架,即使用户的请求随意、含糊或听起来很紧急(“只改一下页眉”“把背景改成蓝色”)。告知用户该 Bundle 尚未搭建,并引导他们先使用experience-ui-bundle-app-coordinate(或experience-ui-bundle-metadata-generate)搭建脚手架。如果用户指定目标 Bundle 后发现它尚未搭建,请停止并引导用户为该 Bundle 搭建脚手架——不要悄悄改为搭建其他候选项。
绝不要臆造、假设或回退使用实际 <sourceDir>/main/default/uiBundles/ 磁盘目录列表中不存在的 Bundle 名称——包括只在其他地方的示例/模板文本(提示词、指令、先前对话)中出现的名称。如果磁盘上的内容与示例不一致,以磁盘内容为准。
确定任务类型
判断请求属于以下哪一类:
| 类别 | 示例 | 实现指南 |
|---|---|---|
| 页面 | 新建路由页面(联系人、仪表板、设置) | references/page.md |
| 页眉 / 页脚 | 全站导航栏、页脚、品牌标识、重命名应用 | references/header-footer.md |
| 组件 | 小部件、卡片、表格、表单、对话框 | references/component.md |
重命名/重新塑造应用品牌的请求(例如“在所有用户可见的地方都称它为 X”)属于页眉 / 页脚任务,即使没有明确提到“页眉”——此类任务至少始终涉及两个文件:src/appLayout.tsx(页眉/导航品牌文字)和 index.html 的 <title>(浏览器标签页标题)。应将其视为一个原子性更改;只更新其中一个的重命名是不完整的。
预构建功能(手动构建前先检查)
某些功能以预构建、经过测试的功能包形式提供。目录会不断更新,无法凭记忆掌握——绝不能仅凭请求措辞判断某项功能「是」或「不是」现成功能。在此技能中手动编写任何非简单功能(超出普通页面、组件或样式更改的范围)之前:
- 查阅权威目录。 调用
experience-ui-bundle-features-generate,它会运行list,显示当前可安装的功能。不要依赖硬编码或记忆中的列表——此技能特意不列出任何功能名称,因为列出的名称都会过时。 - 检测是否已在 bundle 中安装匹配的功能——检查
package.json依赖项和现有的src/文件。如果已安装,不要重新安装或重新实现——但仍必须采用该功能:调用experience-ui-bundle-features-generate对其运行describe(它会读取功能的 README,即采用该功能的约定),将其接入应用;如果该功能附带配置(例如config.json),则根据此应用的数据和使用场景进行设置。已安装但未配置不算完成。 - 如果目录中有匹配功能,但尚未安装,让
experience-ui-bundle-features-generate安装经过测试的功能包。不要在此处从头构建。 - 仅手动构建目录中没有匹配功能的能力。
当此技能作为 experience-ui-bundle-app-coordinate 的一个阶段运行时,匹配功能通常已经存在——由前一阶段安装,或随模板提供。功能已存在不是跳过的理由:步骤 2 仍要求为此应用采用并配置该功能。只有安装或重新实现工作可以跳过——接入和配置绝不能跳过。
布局和导航
appLayout.tsx 是导航和布局的权威来源。所有页面共用此框架。
进行任何影响导航、页眉、页脚、侧边栏、主题或布局的更改时:
- 编辑
src/appLayout.tsx——routes.tsx使用的布局 - 将所有默认或模板导航项和标签替换为应用专属链接和名称
- 在所有位置替换占位应用名称:页眉、导航品牌、页脚,以及
index.html中的<title>
index.html 位于 bundle 根目录(不在 src/ 下),但只要品牌或应用名称发生变化,它仍属于此技能的处理范围——遗留的 <title>React App</title> / Vite + React 样板内容很容易阻碍发布,而 npm run lint/npm run build 都无法检测到。
完成前,请确认:我是否已在 appLayout.tsx 中更新实际导航项和品牌信息?然后运行 node scripts/verify-rules.mjs 检查是否残留样板内容(参见下文“验证”)。
| 内容 | 位置 |
|---|---|
| 布局、导航、品牌 | src/appLayout.tsx |
| 文档标题 | index.html(bundle 根目录,不在 src/ 下——品牌处理仍需覆盖) |
| 根页面内容 | routes.tsx 中根路由对应的组件 |
React 和 TypeScript 标准
路由
只使用一个路由器包。使用 createBrowserRouter / RouterProvider 时,所有导入都必须来自 react-router(而不是 react-router-dom)。
如果应用使用客户端路由器(React Router、Remix Router、Vue Router 等),始终在运行时从文档的 <base href> 标签派生 basename / basepath / base。绝不要对 basename 进行硬编码:
const basename = document.querySelector('base')
? new URL(document.querySelector('base').href).pathname.replace(/\/$/, '')
: '/';
const router = createBrowserRouter(routes, { basename });
组件库和样式
- shadcn/ui 用于组件:
import { Button } from '@/components/ui/button'; - Tailwind CSS 工具类
URL 和路径处理
应用运行在动态基础路径之后。路由器导航(<Link to>、navigate())使用绝对路径(/x)。非路由器属性(<img src>)使用点相对路径(./x)。静态资源优先使用 Vite import。
TypeScript
- 绝不使用
any——应使用适当的类型、泛型,或搭配类型守卫使用unknown - 事件处理器:
(event: React.FormEvent<HTMLFormElement>): void - 状态:
useState<User | null>(null)——始终提供类型参数 - 不使用不安全的类型断言(
obj as User)——应使用类型守卫
模块限制
React UI 包不得导入 Salesforce 平台模块,例如 lightning/* 或 @wire(仅限 LWC)。**在编写任何数据访问代码(GraphQL、REST、SDK 初始化,或获取数据的 hook)之前,必须先调用 experience-ui-bundle-salesforce-data-access 技能。**不要在此技能中编写 fetch/axios 调用,也不要自行编造其他数据 API——即使澄清问题的答案只是顺带暗示了要获取数据,也同样适用。
设计思路
本节和下文“前端美学”中的规则属于创意指导,而非硬性约束——无法通过 lint 或构建检查,只能通过评审而非自动化进行评估。两项硬性且可检查的例外:绝不能默认使用 Inter/Roboto/Arial/Space Grotesk/系统字体;必须支持移动端响应式布局(Tailwind 断点、44px 触控目标),这不是风格偏好。
编码前,先确定鲜明的美学方向:
- **目的:**此界面要解决什么问题?由谁使用?
- **基调:**选择明确的方向——极简主义、极繁主义、复古未来主义、有机、奢华、俏皮、编辑风、粗野主义、装饰艺术、柔和/粉彩、工业风。可将这些作为灵感,但设计应贴合实际情境。
- **差异化:**是什么让人过目难忘?人们会记住哪一点?
选择明确的概念方向,并精准地贯彻执行。大胆的极繁主义和精致的极简主义都可行——关键在于有意为之,而非追求强烈效果。
前端美学
-
**字体:**选择有特色、有个性的字体。将展示字体与精致的正文字体搭配。绝不能默认使用 Inter、Roboto、Arial、Space Grotesk 或系统字体。
-
**颜色:**使用 CSS 变量构建协调的配色方案。主色鲜明并搭配醒目的强调色,效果胜过拘谨、平均分配的配色。避免使用陈词滥调的白底紫色渐变。
-
**动效:**专注于影响力强的时刻——通过错落显示(
animation-delay)精心编排一次页面加载动画,比零散的微交互更能带来惊喜。采用滚动触发和出人意料的悬停状态。优先使用纯 CSS 方案;如果可用,React 项目可使用 Motion 库。 -
**空间构图:**采用出人意料的布局——不对称、重叠、对角流动、打破网格的元素。留出充足的负空间,或进行可控的紧凑布局。
-
**背景与纵深:**营造氛围,不要默认使用纯色。可采用渐变网格、噪点纹理、几何图案、分层透明效果、戏剧性阴影、装饰性边框、颗粒叠加效果。
-
**移动端响应式布局:**所有生成的 UI 都必须支持移动端响应式布局。使用 Tailwind 响应式前缀(
sm:、md:、lg:)适配不同断点下的布局。在小屏幕上将列纵向堆叠,使用灵活的网格,并确保触控目标至少为 44px。测试导航、字体和间距在移动端视口中的表现。
让实现复杂度与美学构想相匹配。极繁主义设计需要精心制作的动画和特效;极简主义设计则需要克制、精准,并仔细处理间距与字体。不同设计不应千篇一律——每次生成都要更换主题、字体和美学风格。
澄清问题
每次只问一个问题,信息足够后就停止提问。
针对页面
- 名称和用途是什么?
- URL 路径是什么?
- 是否应显示在导航中?
- 访问控制是什么?(公开、通过
PrivateRoute验证身份,或通过AuthenticationRoute未验证身份) - 包含哪些内容区块?(列表、表单、表格、详情视图)
- 是否需要获取数据?
对于页眉/页脚
- 需要页眉、页脚,还是两者都需要?
- 包含哪些内容?(徽标、导航链接、用户头像、版权信息、社交图标)
- 页眉是否固定?
- 有什么配色方案或风格方向?
对于组件
- 它应该实现什么功能?
- 它属于哪个页面?
- 是共享/可复用组件,还是仅用于某项功能?
- 需要哪些数据或属性?
- 是否有内部状态?(加载、切换、表单状态)
- 需要使用哪些特定的 shadcn 组件?
验证
完成前,请在已解析的 UI bundle 目录中(见上文“解析 Bundle 目录”)运行以下所有命令:
npm run lint— 必须达到 0 个错误。npm run build— 必须成功。npm run dev(或项目的开发服务器脚本)— 确认应用可以正常启动,以便在运行时验证更改,而不只是通过构建验证。
仅运行 lint/build 无法捕获此技能中风险最高的规则——错误的 react-router-dom 导入、硬编码的 basename、内联 style={{}} 或意外残留的 lightning/* 导入,都可能在 lint 和 build 顺利通过的情况下导致运行时问题。任何涉及路由、布局、样式或模块导入的更改后,都要运行 node scripts/verify-rules.mjs <files-or-dirs-you-edited>:
- 退出码 0:未发现违规。
- 退出码 1,并按规则和文件列出违规项:必须全部修复后,才能认为任务已完成,即使 lint 和 build 已通过也不例外。