# 新建 Catalog 官网实例

[返回目录](../README.md)

本文面向前端接入方，说明如何从 0 新建一个基于 `realibox-ui-sdk` 的官网产品 Catalog。推荐先跑通最小 React/Vite 接入，再按客户品牌和业务字段补齐 `SiteConfig`。

## 前置条件

开始前需要确认这些信息：

| 项目 | 说明 |
| --- | --- |
| SDK key | 调用 `initSDK({ key })` 必填，用于授权校验。 |
| 运行环境 | `development` 连接测试环境，`production` 连接正式环境。 |
| API 地址 | 默认由 `mode` 推导；如客户站点需要代理或私有域名，可用 `apiBaseUrl` 覆盖。 |
| Viewer 地址 | 3D viewer 页面地址，可用 `viewerBaseUrl` 覆盖。 |
| Node / pnpm | 建议 Node.js 18+、pnpm 8+。 |
| 前端项目 | 推荐 React + Vite；SDK 输出的是 Web Components，不是 React 专用组件。 |

## 1. 创建项目并安装 SDK

```bash
pnpm create vite catalog-site --template react-ts
cd catalog-site
pnpm add realibox-ui-sdk
```

客户项目使用 npm 发布包即可；不需要依赖 SDK 仓库内的示例工程。

## 2. 配置环境变量

建议用环境变量管理 SDK key、环境、API 和 viewer 地址：

```bash
VITE_REALIBOX_SDK_KEY=YOUR_SDK_KEY
VITE_REALIBOX_SDK_ENV=production
VITE_REALIBOX_API_BASE_URL=https://api.example.com
VITE_REALIBOX_VIEWER_BASE_URL=https://viewer.example.com/app/mockup_embed_sdk/projects/
VITE_REALIBOX_USE_API_PROXY=true
VITE_REALIBOX_API_PROXY_PATH=/api
VITE_REALIBOX_ROUTER=history
```

上面的域名仅为占位示例，实际值以项目交付的 API 地址和 viewer 地址为准。本地开发推荐使用 Vite proxy，把浏览器请求发到 `/api`，由开发服务器转发到真实 API。生产环境可以继续走同域代理，也可以直接配置允许跨域的 API 域名。

## 3. 初始化 SDK

在应用入口先导入 SDK，再调用 `initSDK`：

```tsx
import { createRoot } from "react-dom/client";
import { initSDK, resolveSDKRuntimeUrls } from "realibox-ui-sdk";
import "realibox-ui-sdk";
import App from "./App";

const runtimeUrls = resolveSDKRuntimeUrls({
  mode: import.meta.env.VITE_REALIBOX_SDK_ENV ?? "production",
  apiBaseUrl: import.meta.env.VITE_REALIBOX_API_BASE_URL,
  viewerBaseUrl: import.meta.env.VITE_REALIBOX_VIEWER_BASE_URL,
  useApiProxy: import.meta.env.VITE_REALIBOX_USE_API_PROXY ?? "true",
  apiProxyPath: import.meta.env.VITE_REALIBOX_API_PROXY_PATH,
});

initSDK({
  key: import.meta.env.VITE_REALIBOX_SDK_KEY,
  mode: runtimeUrls.mode,
  apiBaseUrl: runtimeUrls.browserApiBaseUrl,
  viewerBaseUrl: runtimeUrls.viewerBaseUrl,
  routerMode: import.meta.env.VITE_REALIBOX_ROUTER === "hash" ? "hash" : "history",
});

createRoot(document.getElementById("root")!).render(<App />);
```

`routerMode` 的选择：

| 模式 | 适用场景 |
| --- | --- |
| `"history"` | 有服务器 rewrite 能力，刷新 `/products/xxx` 会回到前端入口。 |
| `"hash"` | 静态 OSS/CDN 托管，无法配置 rewrite，URL 使用 `#/products/xxx`。 |

## 4. 接入列表页和详情页

Catalog 只需要两个整页 Web Components：

```tsx
export function ProductListPage({ siteConfig }: { siteConfig: string }) {
  return <product-list-page site-config={siteConfig} />;
}

export function ProductDetailPage({
  productId,
  siteConfig,
}: {
  productId: string;
  siteConfig: string;
}) {
  return <product-detail-page product-id={productId} site-config={siteConfig} />;
}
```

推荐路由规则：

| 路径 | 页面 |
| --- | --- |
| `/products` | 产品列表页 |
| `/products?category=<code>` | 带分类或主筛选的产品列表页 |
| `/products/:productId` | 产品详情页 |

如果项目使用 React Router，也可以用同样路径渲染这两个组件。示例工程用轻量的 `window.location` 解析，便于静态部署。

## 5. 编写 SiteConfig

推荐在工程里维护 `siteConfig.ts`，这样可以复用常量、按语言生成文案，并获得 TypeScript 类型检查：

```ts
import type { SiteConfig } from "realibox-ui-sdk";

export function createSiteConfig(locale: "zh-CN" | "en"): SiteConfig {
  return {
    locale,
    brand: {
      name: "Example Brand",
      logoUrl: "https://example.com/logo.webp",
    },
    productList: {
      pageSize: 24,
      gridColumns: 3,
      searchPlacement: "header",
      showHeader: true,
      showFooter: true,
    },
    productDetail: {
      galleryLayout: "left",
      recommendLimit: 8,
      showProductCode: false,
    },
  };
}

export function buildSiteConfig(locale: "zh-CN" | "en"): string {
  return JSON.stringify(createSiteConfig(locale));
}
```

什么时候用 JSON：

| 方式 | 适用场景 |
| --- | --- |
| `siteConfig.ts` | React/Vue 工程源码，配置需要多语言、常量复用、类型检查。 |
| JSON 文件 | CMS、低代码、CDN 页面、跨项目迁移，只保存纯数据。 |

配置细节从 [SiteConfig 参数说明](../README.md) 的“按功能查找”开始查；不要直接复制客户示例里的所有字段，先确认该客户真正需要哪些展示差异。

## 6. Vite proxy 配置

本地开发常用配置：

```ts
import react from "@vitejs/plugin-react";
import { defineConfig, loadEnv } from "vite";
import { resolveSDKRuntimeUrls } from "realibox-ui-sdk";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");
  const runtimeUrls = resolveSDKRuntimeUrls({
    mode: env.VITE_REALIBOX_SDK_ENV ?? "production",
    apiBaseUrl: env.VITE_REALIBOX_API_BASE_URL,
    useApiProxy: env.VITE_REALIBOX_USE_API_PROXY ?? "true",
    apiProxyPath: env.VITE_REALIBOX_API_PROXY_PATH,
  });

  return {
    plugins: [react()],
    server: {
      proxy: {
        [runtimeUrls.apiProxyPath]: {
          target: runtimeUrls.apiBaseUrl,
          changeOrigin: true,
          secure: true,
        },
      },
    },
  };
});
```

如果生产环境不使用同域代理，需要后端 API 支持浏览器跨域访问，并确保 SDK key 对目标域名授权。

## 7. 联调清单

上线前至少检查这些路径：

- 列表页能加载产品，分页或 View More 正常。
- 搜索框位置符合 `productList.searchPlacement` 配置。
- 主筛选、普通筛选、推荐类型筛选、3D 筛选生成的请求参数符合预期。
- 详情页可通过列表点击进入，也可直接刷新打开。
- 产品图片、缩略图轮播、推荐产品展示正常。
- 有 3D 项目的产品能加载 viewer，配置器按钮按 `viewerControls` 显示。
- 中英文切换后静态文案和接口数据别名都正确。
- 生产域名下 SDK key、API、viewer 地址均可访问。

## 8. 部署清单

- `history` 路由需要服务器把 `/products` 和 `/products/*` rewrite 到前端入口。
- OSS/CDN 没有 rewrite 时使用 `routerMode: "hash"`。
- 子目录部署要配置 Vite `base`，并确认静态资源路径正确。
- API 代理路径不要与客户站点已有路径冲突。
- `VITE_REALIBOX_SDK_ENV`、`VITE_REALIBOX_API_BASE_URL`、`VITE_REALIBOX_VIEWER_BASE_URL` 在生产构建时必须是正式值。
- 不要把测试 key、测试 API 地址打入正式产物。

## 常见问题

### 页面空白

先确认入口是否 `import "realibox-ui-sdk"`，并且 `initSDK` 在组件渲染前执行。再检查浏览器控制台是否有 SDK key 缺失、接口错误或自定义元素未注册。

### 接口 401 或 403

检查 `VITE_REALIBOX_SDK_KEY`、`mode`、API 地址和授权域名是否匹配。开发环境和生产环境 key 不要混用。

### 筛选项不出现

如果筛选项依赖后端 `/filter-options`，确认后端返回了对应 `code`。配置了 `hideWhenNoOptions: true` 时，后端没有 options 的字段会被隐藏。

### 点击详情后刷新 404

`history` 模式需要服务器 rewrite。无法配置 rewrite 时，把 `routerMode` 改为 `"hash"`。

### React / Vue / HTML 属性名不一致

React / Vue 模板里优先使用 JS 属性名，例如 `projectId`、`siteConfig`。HTML / CDN 直接写标签时使用 kebab-case，例如 `project-id`、`site-config`。
