mcpField
S
sales-app-extensibility

sales-app-extensibility

github.com/vtex开发47847 次安装2 周前更新
代码仓库

关于 sales-app-extensibility

面向 FastStore 项目的 VTEX Sales App 扩展开发与部署技能,指导 Agent 按步骤检查环境、规划需求、生成代码并完成验证和部署。

主要功能

  1. 01检查 FastStore 与 Sales App 前置条件
  2. 02七步扩展开发工作流
  3. 03选择扩展点与 Hook
  4. 04提供界面和 API 扩展模板
  5. 05TypeScript 与静态分析验证
  6. 06文档和部署指导

适用场景

  1. 01搭建购物车促销扩展
  2. 02添加商品详情徽章或推荐
  3. 03将 API 集成到 Sales App 扩展

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vtex/skills --skill sales-app-extensibility

安装后在 Claude Code 中输入/sales-app-extensibility确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
code-templates-and-patterns.md
design-guidelines.md
discovery-and-use-cases.md
documentation-template.md
extension-points-hooks-and-types.md
local-dev-build-and-deploy.md
static-analysis-rules.md

详细介绍

销售应用扩展

适用场景

在构建、自定义或部署 VTEX Sales App 扩展时使用此技能。

  • 为购物车页面添加功能(促销、忠诚度计划、服务)
  • 为商品详情页添加功能(徽章、推荐、保修)
  • 为菜单添加功能(用户资料、导航、指标)
  • 将外部 API 集成到 Sales App 扩展中
  • 生成、搭建或验证 Sales App 扩展代码

以下场景不要使用此技能:

  • 常规 FastStore 店面自定义(使用 faststore-storefront)
  • 构建 VTEX IO 应用(使用 vtex-io-* 技能)
  • Sales App 核心开发或框架修改
前置条件:FastStore 项目

项目根目录必须包含:biome.json、faststore.json、package.json、tsconfig.json、turbo.json。

如果缺少其中任何文件,请停止。用户必须先安装 FastStore:

npx @vtex/fsp-cli init
# Prompt: "What is the application name?" → enter name or press Enter for default
cd <application-name> && yarn

文档:https://beta.fast.store/getting-started

前置条件:Sales App 模块

FastStore 项目中必须存在 Sales App 工作区(通常位于 packages/sales-app),并包含 src/、package.json 和 tsconfig.json。检查根目录 package.json 中的 "workspaces",确认是否包含路径中带有 sales-app 的工作区。若缺少,请停止:

yarn add @vtex/sales-app -D -W
npx fsp create
# Prompts: account name → "Sales App" → path (default or custom)
# Then add the path to root package.json "workspaces" array
yarn install

文档:https://beta.fast.store/sales-app/setting-up

在确认两项前置条件都满足之前,不要继续进行发现或代码生成。

决策规则

严格按照 7 步工作流(步骤 0–6)的顺序执行。不要跳过步骤。

步骤目的条件
0检查前置条件已安装 FastStore + Sales App → 继续;否则停止
1需求发现了解用户想要构建什么
2需求与计划梳理需求 → 生成计划 → 等待用户批准
3代码生成与验证生成 Component.tsx + Component.css(纯 CSS,绝不使用 .module.css)+ index.tsx → 验证
4文档生成 docs/<ExtensionName>.md,说明该扩展
5本地测试提供开发命令和 URL
6构建与部署构建命令 → 部署指南
扩展点选择
扩展点类别可用钩子布局偏移
cart.cart-list.after购物车useCart、useExtension否
cart.cart-item.after购物车useCart、useCartItem、useExtension是
cart.order-summary.after购物车useCart、useExtension是
pdp.sidebar.beforePDPusePDP、useCart、useExtension是
pdp.sidebar.afterPDPusePDP、useCart、useExtension是
pdp.content.afterPDPusePDP、useCart、useExtension是
menu.item菜单useExtension否
menu.drawer-content菜单useCurrentUser、useExtension否
钩子可用性
  • useCart → 所有购物车 + PDP 扩展
  • useCartItem → 仅适用于 cart.cart-item.after
  • useCurrentUser → 仅适用于 menu.drawer-content
  • usePDP → 仅适用于 PDP 扩展
  • useExtension → 所有扩展点
模板选择
  • 无 API + 无钩子 → 简单模板
  • 无 API + 有钩子 → 钩子模板
  • 有 API + 无身份验证 → API 模板
  • 有 API + VTEX IO 代理 → IO 代理模板(推荐)
  • 有 API + 直接身份验证 → 直接身份验证模板(不安全,警告用户)
  • 提供了 API 文档 → 根据提取的响应结构生成 TypeScript 接口;未提供 API 文档 → 使用 ${DATA_INTERFACE} 占位符
API 身份验证策略
  1. 推荐:VTEX IO 代理应用 — IO 应用在服务端存储密钥。扩展使用 credentials: 'include',并通过相对路径访问(/_v/my-api/data)。
  2. 不安全:直接身份验证 — 密钥存储在前端代码中,可在浏览器中查看。仅用于测试和开发。

硬性限制

约束:组件必须返回 JSX.Element,不能返回 null

defineExtensions 需要返回 Element 的 ExtensionPointComponent,而不是 Element | null。

为何重要 返回 null 会导致 TypeScript 编译错误。构建将失败。

检测方式 在任何使用 defineExtensions 注册的组件中出现 return null。

正确

export function MyExtension(): JSX.Element {
  if (!data) return (<></>);
  return <div>{data.value}</div>;
}

错误

export function MyExtension(): JSX.Element | null {
  if (!data) return null;
  return <div>{data.value}</div>;
}
约束:使用前检查可选属性

必须对 CartItem.manualPrice (number | undefined)、CartItem.productRefId (string | undefined)、CartItem.attachments (Attachment[] | undefined) 进行检查。

为何重要 TypeScript 严格模式会拒绝访问可能为 undefined 的值。

检测方式 使用 item.manualPrice、item.productRefId 或 item.attachments 时,没有使用 ?.、??、&& 或 != null。

正确

const price = item.manualPrice ?? item.sellingPrice;
const refId = item.productRefId ?? 'N/A';
const count = item.attachments?.length ?? 0;

错误

const price = item.manualPrice;
const refId = item.productRefId.toUpperCase();
const count = item.attachments.length;
约束:useCartItem().item 可能为 undefined

useCartItem() 返回的 item 类型为 CartItem | undefined。

为何重要 访问 undefined 的属性会导致运行时崩溃。

检测方式 从 useCartItem() 解构出的 item,未经过 if (!item) 检查便被使用。

正确

const { item } = useCartItem();
if (!item) return (<></>);
return <div>{item.name}</div>;

错误

const { item } = useCartItem();
return <div>{item.name}</div>;
约束:index.tsx 中必须使用 defineExtensions

入口点必须使用来自 @vtex/sales-app 的 defineExtensions。

为何重要 如果没有它,构建会成功,但不会渲染任何扩展。

检测方式 index.tsx 中缺少 defineExtensions 导入或调用。

正确

import { defineExtensions } from '@vtex/sales-app';
import { MyExtension } from './components/MyExtension';
export default defineExtensions({ 'cart.cart-list.after': MyExtension });

错误

import { MyExtension } from './components/MyExtension';
export default { 'cart.cart-list.after': MyExtension };
约束:扩展点名称必须完全匹配

ID 是固定集合。不存在的名称会静默失败。

为何重要 扩展不会在任何位置渲染。不会出现构建错误,但运行时不可见。

检测方式 名称不在以下列表中:cart.cart-list.after、cart.cart-item.after、cart.order-summary.after、pdp.sidebar.before、pdp.sidebar.after、pdp.content.after、menu.item、menu.drawer-content。

正确

defineExtensions({ 'cart.cart-list.after': MyExtension });

错误

defineExtensions({ 'cart.list.after': MyExtension });
约束:必须在兼容的扩展点中使用 Hook

每个 Hook 都有 available_in 限制。

为何重要 Hook 上下文只会在特定扩展点中挂载。在其他位置使用会引发运行时错误。

检测方式 在 PDP/menu 中使用 useCartItem。在 cart 中使用 useCurrentUser。在 menu/cart-list 中使用 usePDP。

正确

// useCartItem in cart.cart-item.after ✓
defineExtensions({ 'cart.cart-item.after': ItemWarranty });

错误

// useCartItem in pdp.sidebar.after ✗ — will fail at runtime
defineExtensions({ 'pdp.sidebar.after': ItemWarranty });

推荐模式

工作流概览

步骤 0 — 检查 FastStore + Sales App 的先决条件。若缺少,则停止。

步骤 1 — 探索。根据关键词识别用例,提出后续问题,并确定 API 身份验证策略。如果用户提供了 API 文档(URL、OpenAPI/Swagger 文件、Markdown 或内联文本),则导入文档以提取端点详情和响应结构——跳过相应的手动提问。与用户确认提取的信息。加载探索参考文档,了解详细的问题流程和 API 文档导入部分。

步骤 2 — 将需求映射到扩展点 + hooks + 模板。提供计划,列出要创建的文件:components/<ComponentName>.tsx、components/<ComponentName>.css(纯 CSS——绝不使用 .module.css)和 index.tsx。等待批准。

步骤 3 — 生成 <ComponentName>.tsx、<ComponentName>.css(纯 CSS,绝不使用 .module.css)和 index.tsx。

此步骤所需的参考文档(生成前加载):

  • code-templates-and-patterns.md — 所有组件模板、CSS 模板(内含完整的 Sales App 设计系统:设计令牌、排版、间距、响应式设计)、index.tsx 模板、类型生成规则和自定义 fetch hook 模式。
  • extension-points-hooks-and-types.md — hook 返回类型和 TypeScript 定义。
  • static-analysis-rules.md — @vtex/fsp-analyzer 中的沙箱安全、CSS 隔离和 React 性能规则。对所有生成的文件运行这些检查。
  • design-guidelines.md — 扩展会渲染任何 UI 文本(句首字母大写规则)或使用图标(Phosphor Icons)时加载。

如果在步骤 1 中导入了 API 文档,则根据提取的响应结构生成 TypeScript 接口,并在组件中使用这些接口,而不是 ${DATA_INTERFACE} 占位符。如果扩展会调用 2 个或更多端点,则将 fetch 逻辑提取到自定义 hook 中。根据 code-templates-and-patterns.md 中的 12 项检查清单进行验证。在展示代码之前修复所有违规项;向用户指出警告。

步骤 4 — 在 Sales App 包内生成 docs/<ExtensionName>.md(如有需要,创建 docs/ 文件夹)。加载文档模板参考,了解所需的 9 部分结构和待填写的 Markdown 框架。

步骤 5 — 提供本地开发命令和测试 URL。加载开发/构建/部署参考文档。

步骤 6 — 提供构建命令和部署指南。加载开发/构建/部署参考文档。

参考文件

根据任务需要按需加载这些文件。不要一次性全部加载。

文件加载时机
references/extension-points-hooks-and-types.md选择扩展点、选择钩子、查询 TypeScript 类型(CartItem、ProductSku、Totalizers、Attachment),或检查钩子返回值及其在各扩展点中的可用性时
references/code-templates-and-patterns.md生成扩展代码时——简单、钩子、API、IO Proxy 或 Direct Auth 模板;内嵌完整 Sales App 设计系统(令牌、排版、间距、响应式)的 CSS 模板;包含 defineExtensions 的 index.tsx;钩子初始化;验证清单
references/discovery-and-use-cases.md执行步骤 1(发现)时——用例检测关键词、后续问题、API 身份验证决策树、IO Proxy 与 Direct Auth 流程
references/local-dev-build-and-deploy.md执行步骤 5–6 时——开发服务器命令、测试 URL、构建命令、常见构建错误、FastStore WebOps 部署、监控、回滚
references/static-analysis-rules.md验证生成的代码(步骤 3)时——来自 @vtex/fsp-analyzer 的沙箱安全、CSS 限制和 React 性能规则;包含违规 ID、检测模式及正确/错误示例的完整规则目录
references/design-guidelines.md撰写 UI 文本(句式大小写规则)或使用图标(Phosphor Icons)时。CSS 相关设计规则——令牌、排版、间距、响应式——已直接内嵌在 code-templates-and-patterns.md 的 CSS 模板中,因此生成 CSS 时无需此文件。
references/documentation-template.md在步骤 4 中编写 docs/<ExtensionName>.md 文件时——9 部分结构和 Markdown 模板

常见失败模式

  • 跳过前置检查——未安装 FastStore/Sales App 就生成代码。务必在步骤 1 前确认两者均已安装。
  • 未提供计划——用户可能希望采用其他方案。生成代码前,务必在步骤 2 确认计划。
  • 跳过文档——生成扩展时未附带 docs/<ExtensionName>.md。加载 documentation-template.md 获取必需的结构。
  • 臆造 API 响应类型——生成的接口与实际 API 不符。如果用户提供了文档,请据此推导类型;如果没有,请向用户索取示例 JSON 响应。
  • 忽略用户提供的 API 文档——用户提供了 URL 或文件,但 Agent 仍然手动提问。务必先检查文档,并使用 API 文档导入流程。
  • 使用内联 fetch 请求 2 个或更多端点——在组件主体内调用多个 fetch。将其提取到 hooks/use{Purpose}.ts 中的自定义钩子。
  • 将代码放在 packages/sales-app/src/ 之外——此路径之外的文件不会纳入构建。

代码级违规(DOM API、Node 导入、eval、CSS 限制、React 性能、设计令牌)由 @vtex/fsp-analyzer 强制检查,并会在步骤 3 验证时被捕获。请参阅 static-analysis-rules.md 和 design-guidelines.md。

审核清单

工作流检查点

  • 已安装 FastStore(biome.json、faststore.json、package.json、tsconfig.json、turbo.json)?
  • 已安装 Sales App 模块(sales-app 目录中的 src/、package.json、tsconfig.json)?
  • 已完成探索并确定用例?
  • 用户已批准执行计划?
  • 扩展点有效(来自 8 点参考)?
  • Hooks 与所选扩展点兼容?
  • 已在 docs/<ExtensionName>.md 生成文档(9 个部分,使用 documentation-template.md)?
  • 如果提供了 API 文档,TypeScript 接口是否与文档中的响应结构匹配?
  • 如果使用了 2 个或更多 API 端点,是否已将 fetch 逻辑提取到 hooks/ 中的自定义 Hook?
  • 构建通过:yarn fsp build {account} sales-app?
  • 已在本地测试:yarn fsp dev {account}?

TypeScript / 运行时防护(fsp-analyzer 无法检测)

  • 组件是否返回 JSX.Element,而非 null?
  • 是否对可选属性进行了防护(manualPrice、productRefId、attachments)?
  • 是否检查了 useCartItem().item 是否为 undefined?
  • 是否在 index.tsx 中配置了 defineExtensions?

其他所有代码级规则(沙箱 API、CSS 隔离、React 性能、设计令牌)均由 @vtex/fsp-analyzer 强制执行,并在步骤 3 中检查。请参阅 static-analysis-rules.md 和 design-guidelines.md。

相关技能

  • faststore-storefront — Sales App 之外的 storefront 自定义
  • vtex-io-app-contract — 构建 VTEX IO 代理应用,以实现安全的 API 集成

参考资料

评论

支持 Markdown