关于 experience-ui-bundle-metadata-generate
用于搭建 Salesforce UI bundle 并为受支持框架生成元数据的技能。它要求使用 Salesforce 模板生成器,并指导验证 bundle、配置托管目标与路由,以及生成 CSP Trusted Site 元数据。
主要功能
- 01使用 Salesforce CLI 搭建 bundle
- 02检测受支持的框架
- 03验证 bundle 文件与 API 版本
- 04配置 bundle 元数据和路由
- 05生成 CSP Trusted Site 元数据
适用场景
- 01创建新的 Salesforce UI bundle
- 02准备部署所需的 bundle 元数据
- 03配置路由和输出路径
- 04为 CSP 注册外部域名
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill experience-ui-bundle-metadata-generate安装后在 Claude Code 中输入/experience-ui-bundle-metadata-generate确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/angular-metadata-generate.mdcsp-metadata-format.mdreact-metadata-generate.mdscripts/check-api-version.mjsdetect-framework.mjsverify-bundle-location.mjs详细介绍
UI Bundle 元数据
搭建新的 UI Bundle
必须执行的第一步——绝不可跳过,即使有人要求跳过也不行。 始终运行 sf template generate ui-bundle 来创建新应用,绝不要使用框架 CLI(create-react-app、Vite、Angular CLI)、手写元数据或任何其他替代方案。
即使用户说“只创建元数据”“跳过搭建”“只进行元数据搭建”或“元数据文件就位后就停止”,这一步也仍然是强制的。这些指示描述的是搭建完成后应停止做什么(构建、部署、编写页面),并不意味着可以跳过运行搭建命令本身。.uibundle-meta.xml 和 ui-bundle.json 文件是生成项目之上的配置,而不是项目的替代品。缺少 package.json、src/ 和入口 index.html 的 Bundle 无法构建或部署,即使元数据文件完全正确也不行。
确定框架
此技能支持的框架恰好是 <skill_dir>/references/ 下的参考文件,每个文件都命名为 <framework>-metadata-generate.md(react、angular……)。这是唯一的事实来源——添加框架只需添加参考文件,无需更改此处内容。
以确定的方式检测框架——运行脚本:
node <skill_dir>/scripts/detect-framework.mjs [<ROOT>]
始终通过 node 调用(不要直接运行可执行文件),这样在 Windows cmd/PowerShell 以及 macOS/Linux/Git Bash 上都能正常工作。
ROOT 默认为当前目录;编辑或配置现有 bundle 时,请传入 bundle 或项目根目录。脚本只会输出一个标记,并设置相应的退出代码——根据标记分支处理:
react/angular(退出代码为 0)——打开<skill_dir>/references/<framework>-metadata-generate.md并使用其中的内容。ambiguous(退出代码为 2,检测到两个框架)——询问用户要使用哪一个,然后使用对应的参考文件。unknown(退出代码为 3,没有检测到信号——例如,向尚无 bundle 的项目中搭建全新的 bundle)——回退到调用上下文或用户指定的框架;如果仍无法确定,列出<skill_dir>/references/,从每个文件名中去掉-metadata-generate.md后缀,得出支持的框架列表,并请用户选择。
如果调用上下文或用户已经指定了框架,则以该框架为准,覆盖检测结果——但仍须确认存在对应的参考文件。切勿猜测。
参考文件会提供该框架对应的准确 --template 标记、入口文件布局,以及需要替换的默认样板字符串。
- **UI bundle 名称(
-n):**只能包含字母和数字——不得包含空格、连字符、下划线或特殊字符。 - 使用
--output-dir可将模板生成到其他位置。如果使用了该参数,请在下文第 1 步的验证脚本中传入相同路径。
生成后:
- 验证脚手架是否完整——从项目根目录运行
node <skill_dir>/scripts/verify-bundle-location.mjs <BundleName> [<CustomOutputDir>] [<framework>],并根据任何错误输出采取相应操作。此脚本会同时检查 bundle 的位置,以及是否存在package.json、src/和入口index.html——如果缺少任何一项,则表示跳过了脚手架步骤;请返回并运行sf template generate ui-bundle,然后再继续。仅当搭建脚手架时使用了--output-dir,才传入<CustomOutputDir>(如果要跳过该参数但仍需传入框架,则传入"");传入<framework>(react或angular),以便修复提示使用正确的模板。 - 验证 API 版本——从项目根目录运行
node <skill_dir>/scripts/check-api-version.mjs,确保sfdx-project.json中的sourceApiVersion为 67.0 或更高。脚本会在需要时自动更新该值。 - 替换所有默认样板内容——框架参考文件会列出需要替换的准确默认
<title>和占位字符串。 - 使用实际内容填充主页(着陆区块、横幅、主视觉、导航)。
- 更新导航和占位内容(参阅
experience-ui-bundle-frontend-generate技能)。 - 配置托管目标——如果 UI bundle 的元 XML 中没有
<target>,它将在 org 中不可见。内部应用(App Launcher)请使用experience-ui-bundle-custom-app-generate;外部应用(Experience Site)请使用experience-ui-bundle-site-generate。
在 UI bundle 目录中运行任何脚本之前,始终先安装依赖项。
UIBundle Bundle
UIBundle bundle 必须位于 force-app/main/default/uiBundles/<AppName>/ 下——切勿在 SFDX 项目根目录或任何其他路径中创建。否则,SFDX 部署命令将无法找到它。
bundle 目录必须包含:
<AppName>.uibundle-meta.xml——文件名必须与文件夹名称完全一致- 一个构建输出目录(默认为
dist/),其中至少包含一个文件
元 XML
必填字段:masterLabel、version(最多 20 个字符)、isActive(布尔值)。
可选字段:description(最多 255 个字符)、target。
Target 字段
<target> 元素指定 UI bundle 的托管位置:
| 值 | 用例 | 配套元数据 |
|---|---|---|
Experience | 通过 Digital Experience 面向外部的站点 | Network、CustomSite、DigitalExperienceConfig、DigitalExperienceBundle |
CustomApplication | 通过 Lightning App Launcher 使用的内部应用 | CustomApplication(applications/*.app-meta.xml) |
要让应用可在 Salesforce 组织中访问,必须设置 <target>。未设置 target 的 UI bundle 部署后不会出现在任何位置——没有 App Launcher 条目,也没有 Experience Site URL。请务必将 bundle 与以下其中一项配套使用:
experience-ui-bundle-site-generate(用于Experiencetarget)experience-ui-bundle-custom-app-generate(用于CustomApplicationtarget)
Experience target 示例:
<?xml version="1.0" encoding="UTF-8"?>
<UIBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>propertyrentalapp</masterLabel>
<description>A Salesforce UI Bundle.</description>
<isActive>true</isActive>
<version>1</version>
<target>Experience</target>
</UIBundle>
CustomApplication target 示例:
<?xml version="1.0" encoding="UTF-8"?>
<UIBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>propertymanagementapp</masterLabel>
<description>A Salesforce UI Bundle.</description>
<isActive>true</isActive>
<version>1</version>
<target>CustomApplication</target>
</UIBundle>
ui-bundle.json
可选文件。允许的顶层键:outputDir、routing、headers。
约束:
- 必须是有效的 UTF-8 JSON,最大 100 KB
- 根节点必须是非空对象(不能是
{}、数组或原始值)
路径安全(适用于 outputDir 和 routing.fallback):拒绝反斜杠、以 / 或 \ 开头的路径、.. 路径段、空值/控制字符、glob(*、?、**)和 %。所有解析后的路径都必须位于 bundle 内。
outputDir
引用子目录的非空字符串(不能是 . 或 ./)。目录必须存在且至少包含一个文件。
routing
如果存在,必须是非空对象。允许的键:rewrites、redirects、fallback、trailingSlash、fileBasedRouting。
- trailingSlash:
"always"、"never"或"auto" - fileBasedRouting:布尔值
- fallback:符合路径安全要求的非空字符串;目标文件必须存在
- rewrites:由
{ route?, rewrite }对象组成的非空数组,例如{ "route": "/app/:path*", "rewrite": "/index.html" } - redirects:由
{ route?, redirect, statusCode? }对象组成的非空数组;statusCode 必须为 301、302、307 或 308
headers
由 { source, headers: [{ key, value }] } 对象组成的非空数组。
示例:
{
"routing": {
"rewrites": [{ "route": "/app/:path*", "rewrite": "/index.html" }],
"trailingSlash": "never"
},
"headers": [
{
"source": "/assets/**",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
}
]
}
切勿建议: 将 {} 作为根节点、空的 "routing": {}、空数组、[{}]、"outputDir": "."、"outputDir": "./"。
CSP Trusted Sites
Salesforce 会强制执行内容安全策略(CSP)标头。任何未注册为 CSP Trusted Site 的外部域名都会被拦截(图片无法加载、API 调用失败、字体缺失)。
何时创建
每当应用引用新的外部域名时:CDN 图片、外部字体、第三方 API、地图图块、iframe、外部样式表。
步骤
- 识别外部域名——从代码中的每个外部 URL 提取来源(协议 + 主机)
- 检查现有注册项——查看
force-app/main/default/cspTrustedSites/ - 将资源类型映射到 CSP 指令:
| 资源类型 | 指令字段 |
|---|---|
| 图片 | isApplicableToImgSrc |
| API 调用(fetch、XHR) | isApplicableToConnectSrc |
| 字体 | isApplicableToFontSrc |
| 样式表 | isApplicableToStyleSrc |
| 视频 / 音频 | isApplicableToMediaSrc |
| Iframe | isApplicableToFrameSrc |
对于预检/重定向处理,也始终将 isApplicableToConnectSrc 设为 true。
- 创建元数据文件——按照
references/csp-metadata-format.md中的说明,遵循.cspTrustedSite-meta.xml格式和命名规则。将文件放入force-app/main/default/cspTrustedSites/。