mcpField
V
vtex-io-storefront-theme-app

vtex-io-storefront-theme-app

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

关于 vtex-io-storefront-theme-app

面向构建 VTEX IO 商店前端主题应用的技能,用于组织页面区块、配置自定义路由并管理 Site Editor 可编辑内容。它还说明主题应用、组件应用与商家内容设置之间的职责边界。

主要功能

  1. 01组合页面区块树与模板
  2. 02定义自定义商店前台路由
  3. 03配置 Site Editor 可编辑属性
  4. 04校验区块引用与应用主版本
  5. 05规划主题继承及版本迁移

适用场景

  1. 01搭建商店首页或商品页面布局
  2. 02新增带页面上下文的自定义路由
  3. 03让商家通过 Site Editor 修改页面内容
  4. 04检查区块缺失或主题主版本变更风险

安装

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

$npx skills add https://github.com/vtex/skills --skill vtex-io-storefront-theme-app

安装后在 Claude Code 中输入/vtex-io-storefront-theme-app确认已加载。

详细介绍

店铺主题应用

此技能的适用场景

在处理组装店铺前台的应用时使用此技能——即拥有页面树、自定义路由和店铺 Site Editor 界面的主题应用。

  • 搭建 vendor.store-theme,或任何包含 store builder 且提供页面的应用
  • 添加或修改 store/blocks.json,或 store/blocks/ 下的模板文件
  • 在 store/routes.json 中添加或修改自定义路由
  • 为 store.home、store.product、store.search、store.custom 或任何原生页面模板组合区块树
  • 扩展或覆盖 vtex.store-theme 等基础主题
  • 审查某项更改应归属于主题应用、组件应用还是应用设置

以下情况请勿使用此技能:

  • 在组件应用中注册新区块(store/interfaces.json)——请使用 vtex-io-render-runtime-and-blocks
  • 实现区块背后的 React 组件——请使用 vtex-io-storefront-react
  • 更改 master 上主题应用的已安装版本——请使用 vtex-io-storefront-theme-versioning
  • 本地化字符串——请使用 vtex-io-messages-and-i18n

判断规则

  • 主题应用是常规的 VTEX IO 应用,在 manifest.json 中声明了 store builder。它几乎从不提供 React 代码;它组合由组件应用和基础主题声明的区块。
  • 主题应用在 manifest.json#dependencies 中声明其基础主题,通常为 vtex.store-theme,并继承基础主题提供的所有页面模板、区块声明和默认内容。
  • store/blocks.json(或 store/blocks/ 下的模板文件)通过引用区块 ID,定义每个页面模板的区块树。区块 ID 来自组件应用的 store/interfaces.json,并受声明该区块的应用主版本约束。
  • store/routes.json 定义店铺前台自定义路由,并将其绑定到页面上下文(store.custom、store.product、store.search 等)。原生路由(/、/{slug}/p、搜索)来自基础主题,通常无需重新声明。
  • store/contentSchemas.json 声明区块中可由 Site Editor 编辑的属性。商家对这些属性所做的编辑由 vtex.pages-graphql 存储,存储键中包含主题应用的主版本。
  • 店铺前台行为的更改位置有三处。请审慎选择:
    1. 主题应用的 store/ JSON——组合、路由、默认内容、允许的子项。推广后会立即影响所有顾客。
    2. 组件应用代码——区块的 React 行为。根据组件应用自身的版本发布节奏发布。
    3. Site Editor——商家在主题默认值之上管理的内容覆盖项。由 vtex.pages-graphql 存储,并受声明该区块的应用已安装主版本约束。
  • 优先扩展基础主题,而非分叉基础主题。分叉基础主题后,所有区块、路由和模板的维护责任都将永久转移到你的应用,包括上游错误修复。
  • 店铺前台页面是由区块构成的树。叶节点是组件区块;分支节点是容器区块(flex-layout.row、flex-layout.col 等)。在设计允许的范围内尽量保持树结构浅层;过深的树会增加渲染和内容占用。
  • 按照 vtex-io-storefront-theme-versioning 中的定义,主题应用是一个内容持有应用。其已安装主版本是平台键的一部分,平台会用该键标识商家曾对由此应用声明的区块保存的所有 Site Editor 更改。应将其版本契约视为面向商家的契约,而非面向开发者的契约。

硬性约束

约束:主题应用必须声明 store builder 并依赖一个基础主题

店面主题应用 MUST 在 manifest.json#builders 中声明 "store",并且 MUST 依赖一个基础主题(通常是 vtex.store-theme),除非它明确负责所有原生页面模板、区块和路由。

为什么这很重要

如果没有 store builder,store/ 下的所有文件都不会被处理,主题也不会对店面产生任何影响。如果没有基础主题,应用就必须从头声明每个原生页面模板(store.home、store.product、store.search 等),并且永远负责维护上游内容。

检测

如果主题应用包含 store/blocks.json 或 store/routes.json,但其 manifest 未在 builders 中声明 "store",请 STOP 并添加该 builder。如果 manifest 还在 dependencies 或 peerDependencies 中遗漏了 vtex.store-theme(或其他基础主题),且没有明确说明原因,请 STOP 并确认该应用确实打算负责所有原生模板。

正确

{
  "vendor": "acme",
  "name": "store-theme",
  "version": "1.0.0",
  "title": "ACME Store Theme",
  "builders": {
    "store": "0.x",
    "messages": "1.x"
  },
  "dependencies": {
    "vtex.store-theme": "2.x",
    "acme.product-widgets": "0.x"
  }
}

错误

{
  "vendor": "acme",
  "name": "store-theme",
  "version": "1.0.0",
  "builders": {
    "messages": "1.x"
  },
  "dependencies": {}
}

store/ 文件虽然存在于磁盘上,但平台会忽略它们,而且主题也不会继承任何内容。

约束:store/blocks.json 中的区块 ID 必须能解析到已安装应用中注册的区块

store/blocks.json(或每个模板对应的文件)中引用的每个区块 ID,都 MUST 在某个已安装应用的 interfaces.json 中声明,且该应用的主版本号必须与平台在渲染时解析到的版本一致。无法解析的区块 ID 会在 GraphQL 层导致 Missing block 错误,并使页面无法正常显示。

为什么这很重要

vtex.pages-graphql 会通过在已安装应用中查找 [email protected]:block-id 来解析区块 ID。如果声明该区块的应用未安装,或者其安装的主版本号与商家编写内容时所依据的版本不同,那么从解析器的角度来看,该区块并不存在,页面也就无法渲染。

检测

如果 store/blocks.json 引用了区块 ID,请确认 manifest.json#dependencies 中的某个应用在 store/interfaces.json 中声明了该区块,且版本主号范围与依赖项中列出的范围一致。如果依赖项是 [email protected],该区块必须存在于该应用的 0.x 版本系列中,而不是 5.x 版本系列中。

正确

// manifest.json
{
  "dependencies": {
    "vtex.store-theme": "2.x",
    "acme.product-widgets": "0.x"
  }
}
// store/blocks.json
{
  "store.product": {
    "children": [
      "flex-layout.row#product-main",
      "acme-related-products"
    ]
  },
  "acme-related-products": {
    "props": { "limit": 8 }
  }
}
// [email protected] ships store/interfaces.json with:
{
  "acme-related-products": {
    "component": "RelatedProducts"
  }
}

错误

// manifest.json depends on [email protected]
// but store/blocks.json references a block that only exists in @5.x
{
  "store.product": {
    "children": ["acme-new-related-products"]
  }
}

渲染时解析器会返回 Missing block [email protected]:acme-new-related-products,导致页面无法正常显示。

约束:store/routes.json 中的自定义路由必须绑定到真实的页面上下文和模板

store/routes.json 中的每个条目都 MUST 设置有效的 path、context(或者依赖原生页面 ID(如 store.product)的内置上下文),以及一个存在于区块树中的模板(页面 ID 本身,或在 store/blocks.json 中声明的 store.custom#<id>)。

为什么这很重要

没有可解析模板的路由条目不会渲染任何内容。上下文错误的路由条目(例如,将自定义机构页面指定为 store.product)会执行错误的数据解析器,并导致崩溃或返回空的商品数据。

检测

对于 store/routes.json 中的每个路由,请确认:(a) path 不会与原生 VTEX 路径冲突;(b) 绑定的页面 ID 是 store/blocks.json 中的键;(c) context 与页面实际需要的数据相匹配。

正确

// store/routes.json
{
  "store.custom#about": {
    "path": "/institucional/sobre",
    "context": "vtex.store-resources/InstitutionalPageContext"
  }
}
// store/blocks.json
{
  "store.custom#about": {
    "blocks": ["rich-text#about-body"]
  }
}

错误

// store/routes.json
{
  "store.custom#about": {
    "path": "/p/sobre"
  }
}

路径 /p/sobre 与原生 PDP 路由格式冲突,未声明 context,并且 store/blocks.json 中没有匹配的 store.custom#about 模板。

推荐模式

推荐的主题应用结构:

acme.store-theme/
├── manifest.json                     # store builder, base theme dependency
├── messages/                         # localized strings (separate skill)
└── store/
    ├── blocks.json                   # global block declarations
    ├── routes.json                   # custom routes
    ├── contentSchemas.json           # Site Editor-editable props
    └── blocks/                       # per-template block trees
        ├── home.jsonc
        ├── product.jsonc
        ├── search.jsonc
        ├── category.jsonc
        └── custom/
            ├── about.jsonc
            └── stores.jsonc

推荐的 store.home 组合:

{
  "store.home": {
    "blocks": [
      "flex-layout.row#home-hero",
      "shelf#home-best-sellers",
      "rich-text#home-newsletter"
    ]
  },
  "flex-layout.row#home-hero": {
    "children": ["image#hero-banner"]
  },
  "image#hero-banner": {
    "props": {
      "src": "/arquivos/home-hero.png",
      "alt": "Promotional banner"
    }
  }
}

推荐的自定义机构路由:

// store/routes.json
{
  "store.custom#about": {
    "path": "/institucional/sobre",
    "context": "vtex.store-resources/InstitutionalPageContext"
  }
}
// store/blocks/custom/about.jsonc
{
  "store.custom#about": {
    "blocks": ["flex-layout.row#about-body"]
  },
  "flex-layout.row#about-body": {
    "children": ["rich-text#about-copy"]
  },
  "rich-text#about-copy": {
    "props": {
      "text": "About ACME — see Site Editor for the live copy."
    }
  }
}

推荐的可由 Site Editor 编辑的部分:

// store/contentSchemas.json
{
  "rich-text#about-copy": {
    "type": "object",
    "properties": {
      "text": {
        "type": "string",
        "title": "Body copy",
        "widget": { "ui:widget": "textarea" }
      }
    }
  }
}

商家对 text 的编辑内容由 vtex.pages-graphql 持久化,存储键包含主题应用的 MAJOR 版本。关于主版本升级后这些内容的处理方式,以及如何使用 updateThemeIds mutation 迁移内容,请参阅 vtex-io-storefront-theme-versioning。

常见故障模式

  • 复刻 vtex.store-theme 而不是依赖它,之后将永远无法获得上游的区块修复和路由新增内容。
  • 在 store/blocks.json 中引用的区块 ID 所属声明应用的主版本,与依赖范围允许的版本不一致。
  • 在两个不同的应用中声明相同的区块 ID,导致渲染时的解析结果不确定。
  • 未提供 contentSchemas.json,就直接在 store/blocks.json 的 props 中放置可由 Site Editor 编辑的文案,导致商家无法修改这些内容。
  • 在 store/routes.json 中添加自定义路由,却未在 store/blocks.json 中添加匹配的 store.custom#<id> 模板。
  • 将主题应用的版本视为面向开发者的版本并为“整理”而升级主版本,导致新主版本没有商家内容,并且在 promote 前必须通过 [email protected] 执行 updateThemeIds 迁移(参见 vtex-io-storefront-theme-versioning)。
  • 将 React 组件代码放在主题应用中,而不是专用组件应用中,导致区块声明与区块使用混杂,并增加复用难度。
  • 在主题 store/ 文件中存储运营数据或特定购物者的数据。主题是全局的;特定购物者或特定细分的数据应存放在其他位置。

审查清单

  • manifest.json 是否声明了 store builder?
  • 主题是否依赖基础主题,或者是否明确并有意选择完全负责原生模板?
  • store/blocks.json 中的每个区块 ID,是否都能在已安装应用中找到对应主版本的真实 interfaces.json 条目?
  • store/routes.json 中的每个条目是否都具有有效的 path、context,以及在 store/blocks.json 中匹配的模板?
  • 商家可编辑的文案和图像字段是否通过 contentSchemas.json 提供,而不是硬编码在 props 中?
  • React 组件是否放在专用组件应用中,而非主题应用中?
  • 团队是否考虑过计划中的更改是否会迫使这个承载内容的应用升级主版本?

相关技能

参考

评论

支持 Markdown