跳转到内容

店面概览

店面位于 rCommerce 仓库的 storefront/ 目录,是一个带 React islands 的 Astro 站点。它的设计目标是一套代码服务多家店铺:每家店铺是 一个独立的 Cloudflare Pages 项目,所有店铺差异都通过 PUBLIC_* 环境变量在构建时注入。

生产实例:同一套代码同时服务 store-a.example.com(my-storefront 项目)和 store-b.example.com(store-b-pages 项目)。

品牌身份在构建时由 src/lib/brand/config.ts 解析,并由 Astro 内联 ——不存在运行时切换。

变量作用默认值
PUBLIC_BRAND_SLUG店铺标识(store-a、store-b)——选择对应品牌的页面变体store-a
PUBLIC_BRAND_NAME页头、页脚、邮件中显示的店铺名称My Shop
PUBLIC_BRAND_LOGOpublic/ 下的 logo 路径/images/store-a-logo.png
PUBLIC_BRAND_PRIMARY主题色(Tailwind primary)#2563EB
PUBLIC_BRAND_MENU页头/页脚分类,逗号分隔的 slug:Label 对gear/apparel/accessories
PUBLIC_HERO_VIDEO_URL首页 hero 视频的 Cloudflare Stream iframe 地址hero 视频
PUBLIC_BRAND_HERO_PRODUCT_SLUGhero 面板中展示的商品acme-ceramic-mug
PUBLIC_API_BASE客户端请求使用的后端 API basehttps://api.store-a.example.com/api/v1
RCOMMERCE_API_URL运行时 API 代理的后端源(不带 /api/v1 后缀)—
PUBLIC_AIRWALLEX_ENV结账 Drop-in 的 Airwallex 环境兜底值(demo/prod)demo

未设置时全部回退到示例店铺的默认值,因此不带任何环境变量构建 出来的就是演示店铺。

面向用户的长文案(标语、联系页面、页脚链接与栏目、首页文案、 FAQ)位于 src/lib/brand/:

  • default.ts —— 完整的示例店铺内容,BrandContent 类型的 每个字段都有值。
  • store-b.ts —— 店铺B 的覆盖项,只写不同的字段。
  • index.ts —— 将 defaultContent 与 PUBLIC_BRAND_SLUG 选中的 覆盖模块深合并:
export const content: BrandContent = mergeContent(defaultContent, OVERRIDES[brand.slug]);

未知的 slug 原样回退到默认内容。接入新店铺只需新增一个 <slug>.ts 覆盖模块并注册进 OVERRIDES 映射,无需改动其他代码。 每家店铺必须提供自己的 logo(public/images/<store>-logo.png), 不要用其他店铺的 logo 顶替。

品牌内容中还包含 wooRedirects —— 遗留 WooCommerce 商品 slug 到 规范商品 URL 的映射,参见 SEO 与重定向。

客户端请求直接使用 PUBLIC_API_BASE,但购物车、优惠券、结账等 写操作走同源代理 /api/v1/*(src/pages/api/v1/[...path].ts, 一个 Pages Function)。它运行时转发到 RCOMMERCE_API_URL,避免在 浏览器侧暴露凭据和 CORS 问题。

  • 商品目录:分类导航 + 商品详情页
  • 游客购物车(抽屉式)+ 优惠券
  • 结账:物流选择 + Airwallex Drop-in
  • 账户页面:注册、登录、重置密码、订单历史
  • 按源站(origin)自动生成的 robots.txt、sitemap.xml 和 Google shopping feed
  • 为迁移店铺准备的遗留 WooCommerce URL 301 重定向