关于 frontic-implementation
frontic-implementation 是用于创建和管理 Frontic 区块、列表与页面的技能。它强调先检查数据结构并复用兼容资源,同时指导客户端生成、查询、路由和字段配置。
主要功能
- 01使用前检查资源数据结构
- 02判断复用、扩展或新建
- 03指导区块与列表配置
- 04说明页面和查询的客户端用法
- 05涵盖筛选、排序和字段验证
- 06变更后要求重新生成客户端
适用场景
- 01构建 Frontic 商品列表
- 02将动态路由连接到页面数据
- 03添加筛选、排序或分页
- 04排查字段错误或生成代码过期
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ frontic/ skills --skill frontic-implementation安装后在 Claude Code 中输入/frontic-implementation确认已加载。
详细介绍
Frontic 实现与配置
根据用户请求自主创建或管理区块、列表和页面时,请使用此技能。始终优先使用 Frontic 数据源,而非模拟数据。
开始之前
使用 fetch_api_call 工具检查任何区块、列表或页面的数据结构,然后再使用它。这样可以避免向用户展示不存在的内容或难以辨认的 ID。
1. 资源决策
创建新区块或列表之前,请分析当前的 Frontic 配置:
- 现有区块:可复用或扩展的区块
- 现有列表:符合用户需求的列表——请验证参数兼容性和数据结构
- 可用存储:包含相关数据的存储
复用、扩展还是创建
| 场景 | 操作 |
|---|---|
| 完全匹配(相同的用户流程和参数) | 复用 |
| 接近但不完全匹配 | 扩展(如适用)或创建新的 |
| 参数或意图不同 | 创建新的 |
规则(必须遵守)
- 绝不强行套用:不要将区块或列表用于其设计目标之外的场景,即使是作为权宜之计也不行。
- 参数兼容性是绝对要求:如果某个列表需要参数(例如
categoryId),而用户的使用场景未提供该参数(例如全局搜索),请创建新列表——绝不能使用虚构或占位参数值。 - 用户意图优先:准确匹配用户表达的意图和用户流程。
- 说明你的判断依据:简要说明复用、扩展或创建资源的原因。
⚠️ **警告:**如果你发现自己正使用虚构或默认参数,让现有资源适用于不同的使用场景,请停止。改为创建新资源。
2. 创建区块和列表
创建区块
- 分析数据结构:确定该区块代表的单条记录或实体
- 定义完整架构:纳入所有相关的电商字段
- 规划变体:考虑产品类型、类别等
常见区块: ProductDetail、CategoryDetail、UserProfile、OrderDetail、ReviewDetail、BrandDetail
创建列表
- 确定集合类型:产品、类别、博客文章等
- 确定嵌入的区块:列表必须引用项目中已创建的区块
- 配置筛选条件:价格、类别、品牌、评分、可用性
- 规划排序方式:价格、人气、最新、评分
- 启用搜索:在相关情况下(描述、标题)
- 将参数设为可选,以支持全局使用:如果列表既用于全局搜索,也用于限定范围的场景,请将参数设为可选,并配置默认值:
{
"name": "categoryId",
"dataType": "string",
"required": false,
"defaultValue": "root-id"
}
这样,全局搜索可以使用 listing("GlobalSearch", {}),限定范围的查询则可以使用 listing("GlobalSearch", { categoryId: "xyz" })。
常见列表: ProductListing、CategoryListing、OrderListing、ReviewListing、SearchResults
重新生成客户端
创建或更新区块或列表后,务必重新生成 Frontic Client:
npx @frontic/cli@latest generate
3. Frontic Client 用法
导入客户端(根据应用根目录解析 .frontic/ 路径):
import client from '../../.frontic/generated-client'
区块(按键获取单项)
单项始终通过键来标识。不要编造 'root-category' 之类的占位键,务必使用与该区块关联的存储中的实际键。
const data = await client.block(
'CategoryDetail',
'a3f4b5c6-d7e8-49ab-9c2d-3e4f5e6d7c8b'
)
const data = await client.block(
'ProductDetail',
'123e4567-e89b-12d3-a456-426614174000'
)
列表(支持筛选、排序和分页的集合)
筛选条件和排序选项请参阅 .frontic/query-types.ts 和 .frontic/fetch-api.d.ts。
const products = await client.listing('ProductList', {
categoryId: 'e72b0f5e-1c3d-4a7e-913a-2e4c95cd8f31'
})
const results = await client.listing(
'ProductList',
{ categoryId: '...' },
{
query: {
filter: [
{
type: 'and',
filter: [
{ type: 'equals', field: 'attributes.size', value: '10' },
{ type: 'range', field: 'price.amount', from: 10 }
]
},
{ type: 'range', field: 'price.amount', from: 2000, to: 10000 },
{ type: 'equals', field: 'sale', value: true }
],
sort: { field: 'price.amount', order: 'asc' },
search: 'Red',
page: 1,
limit: 20
}
}
)
页面(按路由获取)
// The route path is the full path including the domain without the protocol
const pageData = await client.page('demo-shop.com/uk/women/shoes')
类型参考
请检查 .frontic/generated-types.d.ts 和 .frontic/query-types.ts,了解区块、列表、页面、参数和返回类型。
4. 页面集成与动态更新
使用页面实现动态路由
除非用户另有要求,否则始终使用页面实现动态路由。页面是由 slug 标识的区块容器。页面 slug 包含域名、区域设置(如果已配置)和路径。区块可以包含用于路由信息的 pageRoute 字段。
对于根级动态路由,创建一个 catch-all 页面,调用 client.page() 并传入拼接后的 slug。单独处理根路径 /(例如使用硬编码区块)。
页面结构层级
Page (e.g. CategoryDetail)
├── Block (e.g. CategoryDetailShopware)
└── Nested Listing (e.g. ProductListShopware)
实现模式
- 初始加载:使用
client.page()或client.block()——它们会提供完整的页面上下文和嵌入内容。 - 筛选/排序/分页:使用
client.listing()——client.page()和client.block()不接受查询参数。
// 1. Initial page load
const pageData = await client.page('domain.com/category-name')
// 2. Dynamic updates — extract params, call embedded listing directly
const categoryId = pageData.data.key
const filteredData = await client.listing('ProductListShopware', { categoryId }, {
query: { filter: [...], sort: {...}, page: 2 }
})
总结: 初始加载始终从 client.page() 开始。对于动态更新,找到嵌套的 listing,从页面数据中提取所需参数,然后使用查询参数调用 client.listing()。仅更新组件状态中的 listing 部分。
5. 字段配置
使用路径命名筛选字段
当筛选字段配置了 path 参数时,查询中必须使用完整的点分路径:
// Configuration:
{ "name": "price", "source": "blockField", "path": "amount" }
// In queries — use "price.amount", NOT "price":
{ "type": "range", "field": "price.amount", "from": 2000, "to": 10000 }
规则: 如果筛选字段有 path: "X",查询中始终将其引用为 fieldName.X。
排序字段配置
Frontic 不支持名称相同但方向不同的重复排序字段。每个排序字段只添加一次——API 会自动同时支持 asc 和 desc。在查询时指定方向:
// One sort field configured, direction chosen per query:
sort: { field: 'price.amount', order: 'asc' } // or 'desc'
字段来源选择
配置搜索、筛选和排序字段时,始终优先选择 blockField,而非 storageField:
- 区块字段已公开且已配置
- 存储字段可能无法访问或类型不正确
- 区块字段可保持与嵌套区块结构的一致性
// Prefer:
{ type: "filter", name: "price", source: "blockField" }
// Avoid:
{ type: "filter", name: "price", source: "storageField" }
验证字段路径
使用筛选或排序字段之前,请验证准确的名称:
- 使用
list_resources查看已配置的字段 - 使用
fetch_api_call测试 listing 并检查响应结构
// Test listing response reveals field structure:
// items: [{ price: { amount: 49595 } }]
// → filter field is "price.amount"
6. 价格格式
Frontic 价格采用带精度的整数格式:
{ "amount": 49595, "currency": "EUR", "precision": 2, "ref": 0 }
显示计算:
const displayPrice = price.amount / Math.pow(10, price.precision)
// 49595 / 100 = 495.95
7. 故障排除
浏览器与构建缓存
重新生成客户端后,缓存可能导致旧代码继续生效。
- 清除框架构建缓存(例如
.next/、.nuxt/、dist/) - 强制刷新浏览器: Cmd+Shift+R(Mac)/Ctrl+Shift+F5(Windows/Linux)
- 在 DevTools 中停用缓存: Network 选项卡 → “Disable cache”