mcpField
F
faststore-overrides

faststore-overrides

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

关于 faststore-overrides

为 FastStore 开发者提供组件和区块覆盖指导,使用官方 Override API 调整原生组件的属性、行为或实现。适用于主题和设计令牌无法满足定制需求的场景。

主要功能

  1. 01使用 getOverriddenSection() 定义覆盖
  2. 02替换原生组件或调整其属性
  3. 03按约定路径和名称组织覆盖文件
  4. 04遵循可覆盖组件与公开 API 限制

适用场景

  1. 01替换商品详情区块中的原生组件
  2. 02为原生区块注入自定义逻辑
  3. 03修改组件属性以适配店铺需求

安装

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

$npx skills add https://github.com/vtex/skills --skill faststore-overrides

安装后在 Claude Code 中输入/faststore-overrides确认已加载。

详细介绍

FastStore 区块与组件覆盖

适用场景

在以下情况下使用此技能:

  • 需要自定义 FastStore 店铺组件的行为或外观,而主题设置和设计令牌无法实现所需效果。
  • 需要用自定义实现完全替换原生组件。
  • 需要在区块内注入自定义逻辑,或修改原生组件的属性。
  • 正在处理 src/components/overrides/ 中的文件。

以下情况不要使用此技能:

  • 仅进行视觉调整(颜色、字体、间距)——请改用 faststore-theming 技能和设计令牌。
  • 为购物车、会话或搜索构建自定义状态管理——请改用 faststore-state-management 技能。
  • 扩展 GraphQL 数据层——请改用 faststore-data-fetching 技能。

决策规则

  • 仅当主题设置无法实现所需更改时才使用覆盖(例如,替换组件、添加逻辑、更改行为)。
  • 要完全替换原生组件时,使用 components 映射,并设置 { Component: CustomComponent }。
  • 只需修改原生组件属性而不替换组件时,使用 components 映射,并设置 { props: { ... } }。
  • 在更改行为的同时进行包装器级样式设置时,使用 getOverriddenSection() 的 className 选项。
  • 纯粹的视觉更改优先使用设计令牌进行主题设置——覆盖的影响范围更大,耦合也更紧密。
  • 仅覆盖 FastStore 原生区块文档中列为可覆盖的组件。未记录的组件名称会被静默忽略。
  • 以 __experimental 为前缀的组件可以覆盖,但无法访问其属性,且这些属性可能会在不另行通知的情况下更改。

硬性约束

约束:使用覆盖 API,绝不修改 FastStore 核心

自定义区块时,必须使用 @faststore/core 中的 getOverriddenSection()。不得直接修改 node_modules/@faststore/ 中的文件,也不得导入内部源文件。

原因 修改 node_modules 是临时性的(运行 npm install 后更改会丢失),而从 @faststore/core/src/ 等内部路径导入会与实现细节紧密耦合,任何 FastStore 更新都可能导致问题。

检测 如果看到从 @faststore/core/src/(内部源文件路径)导入内容 → 立即停止。这些是私有实现细节。只能从公共 API 导入:@faststore/core 和 @faststore/core/experimental。如果看到直接编辑 node_modules/@faststore/ 中的文件 → 立即停止,改用覆盖系统。

正确

// src/components/overrides/ProductDetails.tsx
import { getOverriddenSection } from '@faststore/core'
import { ProductDetailsSection } from '@faststore/core'

import CustomProductTitle from '../CustomProductTitle'

const OverriddenProductDetails = getOverriddenSection({
  Section: ProductDetailsSection,
  components: {
    ProductTitle: { Component: CustomProductTitle },
  },
})

export default OverriddenProductDetails

错误

// WRONG: Importing from internal source paths
import { ProductDetails } from '@faststore/core/src/components/sections/ProductDetails'
// This path is an implementation detail that can change without notice.
// It bypasses the public API and will break on FastStore updates.

// WRONG: Modifying node_modules directly
// Editing node_modules/@faststore/core/dist/components/ProductDetails.js
// Changes are lost on every npm install and cannot be version-controlled.

约束:覆盖文件必须位于 src/components/overrides/

必须将覆盖文件放在 src/components/overrides/ 目录中,并根据要覆盖的区块命名(例如 ProductDetails.tsx)。

原因 FastStore 的构建系统会扫描 src/components/overrides/,以发现并应用区块覆盖。文件放在其他位置将无法被检测到,覆盖也会静默失败——原生区块仍会正常渲染,且不会显示错误信息。

检测 如果在 src/components/overrides/ 之外的文件中看到与覆盖有关的代码(调用 getOverriddenSection)→ 提醒用户该覆盖不会生效。检查文件名是否与 FastStore 区块列表中的有效原生区块名称匹配。

正确

// src/components/overrides/Alert.tsx
// File is in the correct directory and named after the Alert section
import { getOverriddenSection } from '@faststore/core'
import { AlertSection } from '@faststore/core'

import CustomIcon from '../CustomIcon'

const OverriddenAlert = getOverriddenSection({
  Section: AlertSection,
  components: {
    Icon: { Component: CustomIcon },
  },
})

export default OverriddenAlert

错误

// src/components/MyCustomAlert.tsx
// WRONG: File is NOT in src/components/overrides/
// FastStore will NOT discover this override.
// The native Alert section will render unchanged.
import { getOverriddenSection } from '@faststore/core'
import { AlertSection } from '@faststore/core'

const OverriddenAlert = getOverriddenSection({
  Section: AlertSection,
  components: {
    Icon: { Component: CustomIcon },
  },
})

export default OverriddenAlert

约束:仅覆盖文档中列出的可覆盖组件

必须仅覆盖 FastStore 原生区块文档中列为可覆盖的组件。以 __experimental 开头的组件可以覆盖,但无法访问其 props。

为何这很重要 尝试覆盖未列为可覆盖的组件会静默失败。覆盖配置将被忽略,并渲染原生组件。标记为 __experimental 的组件具有不稳定的 props 接口,可能会在未提前通知的情况下发生变化。

检测 如果你在 components 覆盖映射中看到某个组件名称,但它未出现在该区块的 FastStore 可覆盖组件列表中 → 警告该覆盖可能无效。如果组件名称以 __experimental 开头 → 警告其 props 无法访问且不稳定。

正确

// src/components/overrides/ProductDetails.tsx
// ProductTitle is a documented overridable component of ProductDetails section
import { getOverriddenSection } from '@faststore/core'
import { ProductDetailsSection } from '@faststore/core'

const OverriddenProductDetails = getOverriddenSection({
  Section: ProductDetailsSection,
  components: {
    ProductTitle: {
      props: {
        refNumber: true,
        showDiscountBadge: false,
      },
    },
  },
})

export default OverriddenProductDetails

错误

// src/components/overrides/ProductDetails.tsx
// "InternalPriceCalculator" is NOT a documented overridable component
import { getOverriddenSection } from '@faststore/core'
import { ProductDetailsSection } from '@faststore/core'

const OverriddenProductDetails = getOverriddenSection({
  Section: ProductDetailsSection,
  components: {
    // This component name does not exist in the overridable list.
    // The override will be silently ignored.
    InternalPriceCalculator: { Component: MyPriceCalculator },
  },
})

export default OverriddenProductDetails

推荐模式

推荐的文件布局:

src/
├── components/
│   ├── overrides/
│   │   ├── ProductDetails.tsx    ← override file (named after section)
│   │   ├── Alert.tsx
│   │   └── simple-alert.module.scss
│   ├── CustomBuyButton.tsx       ← custom component
│   └── BoldIcon.tsx

最小覆盖 — 替换组件:

// src/components/overrides/ProductDetails.tsx
import { getOverriddenSection } from '@faststore/core'
import { ProductDetailsSection } from '@faststore/core'

import CustomBuyButton from '../CustomBuyButton'

const OverriddenProductDetails = getOverriddenSection({
  Section: ProductDetailsSection,
  components: {
    BuyButton: { Component: CustomBuyButton },
  },
})

export default OverriddenProductDetails

覆盖 props 而不替换组件:

// src/components/overrides/ProductDetails.tsx
import { getOverriddenSection } from '@faststore/core'
import { ProductDetailsSection } from '@faststore/core'

const OverriddenProductDetails = getOverriddenSection({
  Section: ProductDetailsSection,
  components: {
    BuyButton: {
      props: {
        size: 'small',
        iconPosition: 'left',
      },
    },
  },
})

export default OverriddenProductDetails

使用自定义样式进行覆盖:

// src/components/overrides/Alert.tsx
import { getOverriddenSection } from '@faststore/core'
import { AlertSection } from '@faststore/core'
import styles from './simple-alert.module.scss'

import BoldIcon from '../BoldIcon'

const OverriddenAlert = getOverriddenSection({
  Section: AlertSection,
  className: styles.simpleAlert,
  components: {
    Icon: { Component: BoldIcon },
  },
})

export default OverriddenAlert

常见失败原因

  • 对于覆盖系统支持的更改,猴子补丁 node_modules/@faststore/ 或使用 patch-package。安装时更改会丢失,并增加维护负担。
  • 使用 CSS !important 强制实现视觉更改,而不是针对行为更改使用覆盖 API,或针对视觉更改使用设计令牌。
  • 在原生区块外创建包装组件,而不是使用 getOverriddenSection()。包装组件会绕过 CMS 集成、分析跟踪和区块发现。
  • 将覆盖文件放在 src/components/overrides/ 之外 — 这些文件会被静默忽略。
  • 覆盖 FastStore 可覆盖组件文档中未列出的组件名称 — 该覆盖会被静默忽略。

审查清单

  • 覆盖文件是否位于 src/components/overrides/ 中,并以目标区块命名?
  • 文件是否使用了来自 @faststore/core 的 getOverriddenSection()?
  • 所有被覆盖的组件名称是否都在该区块的可覆盖组件文档中列出?
  • 导入是否仅来自 @faststore/core 或 @faststore/core/experimental(而非内部源代码路径)?
  • 这项更改是否可以通过设计令牌实现,而无需覆盖?
  • 覆盖是否以 default 形式导出?

参考

评论

支持 Markdown