Files
ai-mcp-web-ui/_bmad/implementation-artifacts/spec-json-render-phase2.md
Claude AI 89955ab677 feat(spec): json-render Phase 2 - 中低优先级改进规格
- Intent: 4 个中低优先级改进
- Tasks: 5 个详细任务(Props 简化、$computed、createRenderer、watch、repeat)
- Code Map: 4 个文件变更
- 验收标准: 功能/技术/文档三维度

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-25 05:24:12 +00:00

8.7 KiB
Raw Permalink Blame History

json-render Phase 2: 中低优先级改进规格

规格 ID: spec-json-render-phase2 版本: 1.0 状态: 待批准 创建日期: 2026-03-25 迭代: 2/3


Intent

本规格包含 json-render v0.15.0 迁移的中低优先级改进,这些改进不是架构迁移的核心,但能显著提升开发体验和代码质量:

  1. 组件 Props 类型简化 - 使用 json-shorthand-prop-types 简化 Props 定义
  2. $computed 函数支持 - 在 JSON UI 中支持计算属性
  3. createRenderer API 采用 - 使用新的渲染器创建 API
  4. watch/repeat 属性支持 - 添加响应式和重复渲染能力

Approach

阶段 1: Props 类型简化

使用 @json-render/shorthand-prop-types 简化组件 Props 定义:

// 简化前
import { z } from 'zod';
const CardSchema = z.object({
  title: z.string().optional(),
  description: z.string().optional(),
  children: z.array(z.any()).optional(),
});
type CardProps = z.infer<typeof CardSchema>;

// 简化后
import { s } from '@json-render/shorthand-prop-types';
const CardSchema = {
  title: s.string.optional,
  description: s.string.optional,
  children: s.array.optional,
};

阶段 2: $computed 函数集成

JSONUIProvider 中添加 functions prop支持计算属性

<JSONUIProvider
  functions={{
    formatDate: (date: string) => new Date(date).toLocaleDateString('zh-CN'),
    formatCurrency: (amount: number) => ${amount.toFixed(2)}`,
    pluralize: (count: number, singular: string, plural: string) =>
      count === 1 ? singular : plural,
  }}
>
  <JsonRenderer spec={spec} />
</JSONUIProvider>

阶段 3: createRenderer 迁移

使用 createRenderer API 简化渲染器创建:

// 简化前
const JsonRenderer = ({ spec }: { spec: JsonSpec }) => {
  return (
    <JSONUIProvider>
      <ComponentRenderer spec={spec} />
    </JSONUIProvider>
  );
};

// 简化后
import { createRenderer } from '@json-render/core';
const JsonRenderer = createRenderer();

阶段 4: watch/repeat 支持

添加响应式和重复渲染能力:

// watch - 响应式更新
const specWithWatch = {
  type: 'text',
  content: '$formatDate(data.createdAt)',
  watch: ['data.createdAt'], // 依赖变化时重新渲染
};

// repeat - 列表渲染
const specWithRepeat = {
  type: 'stack',
  repeat: {
    items: '$data.items', // 数据源
    template: {           // 每项的模板
      type: 'card',
      title: '$item.name',
    },
  },
};

Tasks

Task 1: 简化组件 Props 类型定义

文件: frontend-v2/lib/json-render-catalog.tsx

操作:

  1. 移除 z.infer 类型推导
  2. 使用简化类型直接定义 Props
  3. 保持 Zod Schema 用于运行时验证

代码变更:

// 当前代码
import { z } from 'zod';

export const CardSchema = z.object({
  title: z.string().optional(),
  description: z.string().optional(),
  children: z.array(z.any()).optional(),
});
export type CardProps = z.infer<typeof CardSchema>;

// 简化后
export const CardSchema = z.object({
  title: z.string().optional(),
  description: z.string().optional(),
  children: z.array(z.any()).optional(),
});

export type JsonRenderProps = {
  title?: string;
  description?: string;
  children?: JsonSpec[];
};

验收标准:

  • 组件 Props 类型定义简洁
  • 运行时验证仍然有效
  • TypeScript 类型检查通过

Task 2: 在 JSONUIProvider 中添加 functions prop

文件: frontend-v2/components/JsonRenderer.tsx

操作:

  1. 添加 functions prop 到 JSONUIProvider
  2. 将 functions 传递给 ComponentRenderer
  3. 在表达式求值时支持函数调用

代码变更:

// JsonRenderer.tsx
interface JSONUIProviderProps {
  children: React.ReactNode;
  functions?: Record<string, (...args: any[]) => any>;
}

export const JSONUIProvider: React.FC<JSONUIProviderProps> = ({
  children,
  functions = {},
}) => {
  const contextValue = useMemo(
    () => ({ functions }),
    [functions]
  );

  return (
    <JsonRenderContext.Provider value={contextValue}>
      {children}
    </JsonRenderContext.Provider>
  );
};

验收标准:

  • 可以在 spec 中使用 $formatDate() 等函数
  • 函数调用正确传递参数
  • 函数执行错误有友好提示

Task 3: 迁移到 createRenderer API

文件: frontend-v2/components/JsonRenderer.tsx

操作:

  1. 使用 createRenderer 替换手动 Provider 包装
  2. 简化组件结构
  3. 保持向后兼容

代码变更:

// 迁移前
export const JsonRenderer: React.FC<JsonRendererProps> = ({ spec }) => {
  return (
    <JSONUIProvider>
      <ComponentRenderer spec={spec} />
    </JSONUIProvider>
  );
};

// 迁移后
import { createRenderer } from '@json-render/core';
export const JsonRenderer = createRenderer();

验收标准:

  • 代码量减少
  • 功能保持不变
  • 现有组件正常工作

Task 4: 添加 watch 属性支持

文件: frontend-v2/lib/json-render-catalog.tsx

操作:

  1. 扩展 JsonSchema 类型,添加 watch 属性
  2. ComponentRenderer 中实现 watch 逻辑
  3. 使用 React hooks 监听依赖变化

代码变更:

// 扩展类型
export interface WatchableSchema extends JsonSchema {
  watch?: string[]; // 依赖路径
}

// ComponentRenderer 中的实现
export const ComponentRenderer: React.FC<RendererProps> = ({ spec }) => {
  const watchDeps = spec.watch || [];
  const [data, setData] = useState(contextData);

  useEffect(() => {
    // 监听依赖变化
    const unsubscribe = watchDependencies(watchDeps, (newData) => {
      setData(newData);
    });
    return unsubscribe;
  }, [watchDeps]);

  return <ConcreteComponent {...spec} data={data} />;
};

验收标准:

  • watch 属性正确触发重新渲染
  • 依赖路径支持嵌套访问
  • 无内存泄漏

Task 5: 添加 repeat 属性支持

文件: frontend-v2/lib/json-render-catalog.tsx

操作:

  1. 扩展 JsonSchema 类型,添加 repeat 属性
  2. ComponentRenderer 中实现 repeat 逻辑
  3. 支持动态列表渲染

代码变更:

// 扩展类型
export interface RepeatableSchema extends JsonSchema {
  repeat?: {
    items: string | any[]; // 数据源路径或数组
    template: JsonSchema;  // 每项的模板
    key?: string;          // 唯一键字段
  };
}

// ComponentRenderer 中的实现
export const ComponentRenderer: React.FC<RendererProps> = ({ spec, data }) => {
  if (spec.repeat) {
    const items = typeof spec.repeat.items === 'string'
      ? get(data, spec.repeat.items)
      : spec.repeat.items;

    return (
      <>
        {items.map((item, index) => (
          <JsonRenderer
            key={spec.repeat.key ? item[spec.repeat.key] : index}
            spec={spec.repeat.template}
            data={{ ...data, item }}
          />
        ))}
      </>
    );
  }

  return <ConcreteComponent {...spec} />;
};

验收标准:

  • repeat 属性正确渲染列表
  • 支持嵌套路径访问
  • key 属性正确工作

Code Map

文件 变更类型 描述
frontend-v2/lib/json-render-catalog.tsx 修改 简化 Props 类型,添加 watch/repeat 支持
frontend-v2/lib/json-render-registry.tsx 修改 更新组件注册方式
frontend-v2/components/JsonRenderer.tsx 修改 添加 functions prop迁移到 createRenderer
frontend-v2/app/page.tsx 修改 更新使用方式

验收标准

功能验收

  • 所有组件使用简化的 Props 类型
  • $computed 函数在 spec 中可用
  • watch 属性正确触发重新渲染
  • repeat 属性正确渲染列表

技术验收

  • TypeScript 类型检查通过
  • 运行时验证仍然有效
  • 性能无明显下降
  • 无内存泄漏

文档验收

  • 更新 JSON_RENDER_USAGE.md
  • 添加 $computed 函数文档
  • 添加 watch/repeat 使用示例

依赖关系

本规格依赖于 Phase 1 的完成:

  • Phase 1 完成后,本规格可以独立实施
  • 部分功能(如 watch/repeat可能需要 Phase 1 的基础设施

时间估算

Task 预估时间
Task 1: Props 简化 2 小时
Task 2: $computed 集成 3 小时
Task 3: createRenderer 迁移 2 小时
Task 4: watch 支持 4 小时
Task 5: repeat 支持 4 小时
总计 15 小时

批准记录

字段
批准者
批准日期
批准理由

变更历史

日期 版本 变更内容 作者
2026-03-25 1.0 初始版本 外层 BMAD 专家