前端基于JSON Schema 配置驱动的DSL架构实践

概述

基于领域模型概念设计了一套配置驱动的DSL(Domain Specific Language)模板配置系统 ,通过JSON Schema(核心)配置文件驱动页面生成,实现了高度可配置化的管理系统。该架构采用模型-项目继承设计,支持多项目、多领域的复杂业务场景,有效解决了传统前端开发中的70-80%的重复性工作和维护难题。

一、核心设计理念

1.1 配置驱动开发

通过一套标准化的配置数据即可驱动生成整个站点的页面组件,将"手写代码"转变为"配置生成",大幅提升开发效率。

1.2 模型继承机制

基础模型配置可被多个项目继承和扩展(设计灵感来源于面向对象思维),支持内容沉淀的同时保持可定制化灵活性,遵循DRY (Don't repeat yourself) 原则。

1.3 组件化架构

基于Vue 3的响应式组件化架构,支持动态组件渲染和组合,确保良好的可维护性和扩展性。

1.4 领域分离

按业务领域组织模型配置,不同领域可派生出对应的项目类型,保持业务逻辑的清晰分离。

二、解决的核心痛点

2.1 重复性CRUD开发

传统痛点:每个业务模块都需要重复编写表格、搜索、增删改查的代码,而实际上的区别大多数情况下都是字段和数据源不同。

解决方案:通过对 JSON Schema 进行拓展,使其可用于配置自动生成完整的CRUD界面

JSON 复制代码
// Schema 配置设计模板
schemaConfig: {
      api: '', //数据源api (遵循 RESTFUL 规范)
      schema: { // 模板数据结构
        type: 'object',
        properties: {
          key: {
            ...schema, // 标准的 json schema 配置
            type: "", // 字段类型
            label: '', // 字段的中文名
            //对应字段在 table 中的相关配置 
            tableOption: {
              ...elTableConfigColumn, // 标准的el-table-column 配置内容
              visible: true, // 默认为true, (false或不配置的时候,表示不在表单中显示)
              ..., //可自行设计对数据处理的配置,如:toFixed:2 小数表示保留两位;
            },
            // 字段在search-bar 中的相关配置
            searchOption: {
              ...eleComponentConfig, // 标准的 el-component-config 配置
              comType: '', // 配置组件类型 input select ...
              default: '', // 默认值,
              ..., //可拓展,不同组件类型 对应的配置设计
            },
            ...,// 可拓展,表单配置 formOption ...
          },
          ...
        },
      },
      // table 相关配置,
      tableConfig: {
        headerButtons: [
          ...,
        ],
        // 表格中每行按钮设计
        rowButtons: [
          {
            label: '',//按钮中文名称
            eventKey: '', // 按钮事件名
            // 按钮事件具体配置
            eventOption: {
                ...
            },
            ...elButtonOption, //标准el-button 配置
          },
          ...
        ]
      },
      searchConfig: {}, // search-bar 搜索框相关配置,
      components: {},  // 模块组件

    },

2.2 组件复用困难

传统痛点:不同页面的表格、搜索组件功能差异大,难以复用

解决方案:通过tableOption、searchOption等标准化配置实现组件的灵活定制

2.3 状态管理复杂

传统痛点:搜索条件、分页状态、选中状态需要手动管理

解决方案:自动处理URL参数与搜索默认值的映射,实现状态持久化; 如:给keyword字段添加默认值 url:xxx/xxx?keyword=默认值

三、架构设计

graph TD model基础模板配置 --> project继承 project继承 --> bff层处理 bff层处理 --> dashborad模板引擎解析 dashborad模板引擎解析 --> 页面组件渲染 页面组件渲染 --> 菜单系统 页面组件渲染 --> 路由管理

四、核心技术实现

4.1 配置继承机制

js 复制代码
model/ 
├── business/ # 电商领域
│ ├── model.js # 基础模型配置 
│ └── project/ # 具体项目配置 
│   ├── pdd.js # 拼多多项目 
│   ├── jd.js # 京东项目 
│   └── taobao.js # 淘宝项目 
├── course/ # 课程领域 
│ ├── model.js # 基础模型配置 
│ └── project/ # 具体项目配置 
│    ├── bilibili.js # B站项目 
│    └── douyin.js # 抖音项目 
└── index.js # 模型加载器

// 实际案例:
/**
 *  项目继承model 
 * @param {object} model model 配置
 * @param {object} project project 配置
 * @returns {object} 继承后的 project 配置
 * 
 */
const projectExtendModel = (model, project) => {
  return _.mergeWith({}, model, project, (modelVal, projVal) => {
    // 处理数组合并的特殊情况
    if (Array.isArray(modelVal) && Array.isArray(projVal)) {
      let result = [];

      // 因为project 继承 model , 所以需要处理修改和新增内容的情况
      // 情况一  project 有的键值, model 也有 则为 修改 (重载)
      // 情况二  project 有的键值, model 没有 则为 新增 (拓展)
      // 情况三  project 没有的键值, model 有 则为 保留 (继承)
       for (let i = 0; i < modelVal.length; ++i) {
        const modelItem = modelVal[i];
        const projItem = projVal.find(item => item.key === modelItem.key);

        // 情况一  修改 情况三 继承
        result.push(projItem ? projectExtendModel(modelItem, projItem) : modelItem)
      }

      for (let i = 0; i < projVal.length; ++i) {
        const projItem = projVal[i];
        const modelItem = modelVal.find(item => item.key === projItem.key);

        // 情况二 新增
        if (!modelItem) {
          result.push(projItem)
        }
      }
      
      return result;

    }

  })
}

4.2 动态组件渲染

Schema配置解析

通过schema.js实现配置数据的智能解析和转换:

js 复制代码
  // 基础模型 (model/business/model.js)

 menu: [
    {
      key: 'product',
      name: '商品管理',
      schemaConfig:{
         ...,// 基础配置
      }
    },
  ]
  
 //项目配置(model/business/project/pdd.js)
  name: '拼多多',
  menu: [
    {
      key: 'product',
      name: '商品管理(拼多多)'
    },
     {
      key: 'client',
      name: '客户管理(拼多多)'
    },
  ]

SchemaOption的清洗和过滤

为了在渲染时,把保留对应组件的相关配置,剔除无用的配置,需要进行以下的处理:

js 复制代码
  // 通用构建schema  方法 (消除噪音)
  const buildDtoSchema = (_schema, comName) => {
    if (!_schema?.properties) return

    const dtoSchema = {
      type: 'object',
      properties: {}
    }

    //提取有效 schema 字段信息
    for (const key in _schema.properties) {
      const props = _schema.properties[key]
      // tableOption searchBarOption formOption
      if (props[`${comName}Option`]) {
        let dtoProps = {};
        // 提取 props 中 非option的部分 存放到dtoProps中
        for (const pKey in props) {
          if (pKey.indexOf('Option') < 0) {
            dtoProps[pKey] = props[pKey]
          }
        }
        // 处理conName Option
        dtoProps = Object.assign({}, dtoProps, { option: props[`${comName}Option`] });
        dtoSchema.properties[key] = dtoProps;
      }

    }

    return dtoSchema
  }

4.3 路由和视图管理

视图组件架构

  • header-view: 头部菜单渲染,支持项目切换和多级菜单

  • sider-view: 侧边栏复合视图,支持嵌套路由和默认选中

  • schema-view: 配置驱动的CRUD页面核心组件

  • iframe-view: 外部页面嵌入支持

4.4 Schema 配置解析于数据流转

graph TD A[原始 Schema 配置] --> B[useSchema Hook] B --> C[buildDtoSchema 处理] C --> D[tableSchema 分离] C --> E[searchSchema 分离] C --> Q[formSchema... 分离操作] D --> F[SchemaTable 组件] F --> G[表格列动态生成] F --> H[数据格式化处理] F --> I[分页和操作按钮] E --> J[SchemaSearchBar 组件] J --> K[动态组件渲染] K --> L[SearchItemConfig 映射] L --> M[input] L --> N[select] L --> O[dynamicSelect] L --> P[... 额外拓展组件]

动态组件注册

js 复制代码
//组件配置映射
const SearchItemConfig = {
  input: {
    component: Input
  },
  select: {
    component: Select
  },
  dynamicSelect: {
    component: DynamicSelect
  },
  dateRange: {
    component: DateRange
  },
  ...,//后续组件拓展可在此处进行,无需修改核心代码,只需扩展配置
}

// 动态组件渲染 
<component
    :is="SearchItemConfig[schemaItem.option?.comType]?.component"
    :ref="handleSearchComList"
    :schema-key="key"
    :schema="schemaItem"
    @loaded="handleChildLoaded"
    />

4.5 数据请求与状态管理流程

五、实践案例与效果展示

5.1 多项目配置继承实例

以拼多多项目为例,展示完整的配置继承效果:

5.2 实际配置效果对比

一份配置,多端复用:

js 复制代码
// 同一份商品配置,在不同项目中的表现 
// 淘宝项目:展示"淘宝商品管理" 
// 京东项目:展示"京东商品管理" 
// 拼多多项目:展示"拼多多商品管理" + 额外的客户管理功能

总结

这套基于配置驱动的DSL架构通过以下核心实现:

  1. 配置即代码:将70-80%的重复性开发工作转化为配置编写

  2. 模型继承:基于面向对象思维的继承机制

  3. 组件化:高度解耦的动态组件渲染系统

  4. 标准化:基于JSON Schema的标准配置进行拓展的规范

相关推荐
星栈4 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
前端·后端·全栈
anyup4 小时前
uni-app X 全屏引导页组件,一套支持 App、H5、小程序多端引导
前端·架构·uni-app
a1117765 小时前
动森UI组件(开源 html animal-island-ui )
前端·javascript·ui·开源·html
KaMeidebaby5 小时前
卡梅德生物技术快报|真核蛋白表达信号肽筛选实验全流程复盘
服务器·前端·数据库·人工智能·算法
万少5 小时前
万少的 Claude Code 入门教程
前端·人工智能·后端
এ慕ོ冬℘゜6 小时前
JS 前端基础高频面试题
开发语言·前端·javascript
放下华子我只抽RuiKe56 小时前
React 从入门到生产(八):测试与部署
前端·javascript·深度学习·react.js·前端框架·ecmascript·集成学习
蜡笔小电芯6 小时前
【Electron】第2章—BrowserWindow 与 Electron 窗口机制
前端·javascript·electron
zhangxingchao6 小时前
AI 大模型面试核心二:微调、RAG、MCP、Agent 与工程落地
前端·人工智能·后端