
1. 中后台前端为什么总在重复造轮子如果你做过三年以上的中后台系统大概率经历过这样的场景新项目立项产品经理甩过来一份原型图你打开一看表格、表单、弹窗、树形选择器、日期范围、附件上传……全是上个项目已经写过一遍的东西。于是你从旧项目里复制粘贴改改样式调调接口两周后勉强跑起来但代码里已经埋下了三套不同风格的按钮和两套互相打架的表单校验逻辑。这就是中后台前端最真实的痛点业务复杂、产品独立、交付周期短但 UI 层却高度重复。传统的 HTML CSS 手写方式在页面数量超过二十个之后基本就失控了。组件化的思路大家都懂但真正难的是——组件库能不能覆盖中后台那些“脏活累活”比如数据源管理、字段级配置、多层级属性复用、国际化、主题定制。Choerodon UI 就是在这个背景下出现的。它是汉得自研的开源企业级 React 组件库核心不是“又一套 Ant Design 的替代品”而是围绕中后台场景做了两件关键的事一是自研 DataSet 数据源把数据流转和组件交互打通二是提供全局、模块、组件、字段四层配置体系让复用真正落地。它已经稳定支撑了汉得 HZERO 中台体系下的上千个项目提供 90 开箱即用的 React 组件。这篇文章面向的是正在评估或准备接入 Choerodon UI 的前端团队。我会从工程初始化开始给出可复制的配置片段、主题变量覆盖示例、组件按需引入的验证步骤以及接入过程中最容易踩的报错排查。你不需要先成为它的专家跟着操作就能跑起来。2. Choerodon UI 接入前的环境与依赖准备在动手之前先把“前置条件”理清楚。Choerodon UI 是一个 React 组件库所以你的项目需要是 React 技术栈。官方推荐 React 16.8 及以上版本因为内部大量使用了 Hooks。如果你还在用 class 组件为主的老项目也可以接入但 DataSet 相关的 hooks 用法会受限。Node 版本建议 16 或 18npm 用 8 以上或者直接用 pnpm/yarn。我实测下来pnpm 在安装这种组件库时速度更快而且对 peerDependencies 的处理更干净。下面以 pnpm 为例。第一步创建一个标准的 React 工程。如果你已经有项目跳过这步。pnpm create vite choerodon-demo --template react-ts cd choerodon-demo pnpm install这里用 Vite 而不是 CRA原因是 Vite 的启动速度和按需引入配合更好而且 Choerodon UI 的样式文件在 Vite 下处理更顺滑。创建完成后安装 Choerodon UI 核心包pnpm add choerodon-ui注意Choerodon UI 的包名就是choerodon-ui不是choerodon/ui。安装完成后你会在node_modules/choerodon-ui下看到lib、es、dist三个目录。es是 ES Module 版本按需引入时走这个目录dist是 UMD 版本一般用于 script 标签直接引入。接下来是样式。Choerodon UI 的样式分两部分基础样式和主题样式。基础样式必须引入否则组件会“裸奔”。在src/main.tsx里加入import choerodon-ui/dist/choerodon-ui.css;如果你只想用默认主题这一行就够了。但如果你要做主题定制后面会讲怎么用 CSS 变量覆盖。还有一个容易被忽略的点Choerodon UI 依赖mobx和mobx-react-lite来做 DataSet 的响应式更新。虽然安装choerodon-ui时会自动带上但如果你项目里已经装了不同版本的 mobx可能会冲突。建议在package.json里显式锁定{ dependencies: { choerodon-ui: ^1.6.0, mobx: ^6.10.0, mobx-react-lite: ^4.0.0 } }版本号以你实际安装的为准这里只是示意。锁定的目的是避免 mobx 5 和 6 的 API 差异导致 DataSet 不更新。环境准备好之后先别急着写业务组件。我建议先跑一个最小验证引入一个 Button 和一个 DataSet确认样式和响应式都正常。下一节会给出完整的可复制配置。3. 可复制的工程配置与主题变量覆盖这一节是全文的核心操作部分。我会给出三份可直接复制的配置Vite 配置、主题变量覆盖文件、以及一个带 DataSet 的组件示例。先看 Vite 配置。Choerodon UI 的 ES 模块在 Vite 下需要做一点optimizeDeps处理否则首次启动时可能报 “Cannot find module choerodon-ui/es/...”。在vite.config.ts里import { defineConfig } from vite; import react from vitejs/plugin-react; export default defineConfig({ plugins: [react()], optimizeDeps: { include: [choerodon-ui, choerodon-ui/es/**/*], }, css: { preprocessorOptions: { less: { javascriptEnabled: true, }, }, }, });javascriptEnabled是为 Less 主题变量准备的。Choerodon UI 的主题底层用 Less 变量但对外暴露的是 CSS 变量所以即使你不用 Less加上这行也不会有副作用。接下来是主题变量覆盖。Choerodon UI 内置了鲸海蓝、凌莺蓝、冰峰白、风铃紫等官方主题但实际项目里品牌色往往不一样。最推荐的方式是 CSS 变量覆盖而不是去改 Less 源码。在src/styles/theme.css里:root { --c7n-primary-color: #2f54eb; --c7n-primary-color-hover: #4c6ef5; --c7n-primary-color-active: #1d39c4; --c7n-border-radius-base: 4px; --c7n-font-size-base: 14px; --c7n-text-color: #1f2329; --c7n-text-color-secondary: #646a73; --c7n-background-color: #ffffff; --c7n-component-background: #ffffff; --c7n-table-header-bg: #f5f6f7; }然后在main.tsx里把主题文件放在 Choerodon UI 基础样式之后引入import choerodon-ui/dist/choerodon-ui.css; import ./styles/theme.css;顺序很重要。如果主题文件在前基础样式会覆盖你的变量。我踩过一次坑调了半天发现是引入顺序反了。如果你需要更细粒度的主题比如只改某个模块下的按钮颜色可以用模块级配置。Choerodon UI 支持在组件外层包一个ConfigProviderimport { ConfigProvider } from choerodon-ui; ConfigProvider theme{{ primaryColor: #2f54eb }} App / /ConfigProvider但注意ConfigProvider的 theme 属性和 CSS 变量是两套机制。CSS 变量优先级更高适合全局品牌色ConfigProvider适合运行时动态切换。两者不要混用同一个变量否则排查起来很痛苦。最后是一个带 DataSet 的组件示例。这个示例同时验证了按需引入、DataSet 响应式和主题生效import React from react; import { Button, Table, DataSet } from choerodon-ui/pro; const dataSet new DataSet({ autoQuery: true, fields: [ { name: name, type: string, label: 姓名 }, { name: age, type: number, label: 年龄 }, { name: dept, type: string, label: 部门 }, ], queryFields: [ { name: name, type: string, label: 姓名 }, ], transport: { read: { url: /api/users, method: get, }, }, }); const UserTable () { return ( div style{{ padding: 24 }} Button colorprimary onClick{() dataSet.query()} 刷新数据 /Button Table dataSet{dataSet} columns{[ { name: name, width: 120 }, { name: age, width: 80 }, { name: dept, width: 160 }, ]} / /div ); }; export default UserTable;这里Table的dataSet属性直接绑定 DataSet数据加载、分页、排序都由 DataSet 管理你不需要在组件里写useState和useEffect。这就是 Choerodon UI 数据驱动的核心组件不持有数据DataSet 持有数据组件只负责渲染。4. 验证请求与成功结果确认配置写完之后必须验证三件事组件是否正常渲染、DataSet 请求是否发出、主题变量是否生效。这一节给出具体的验证步骤和预期结果。先启动项目pnpm dev打开浏览器访问 Vite 提示的地址通常是http://localhost:5173。如果页面白屏先看控制台有没有报错。最常见的白屏原因是样式没引入或者choerodon-ui的 ES 模块解析失败。前者表现为组件无样式但能渲染后者表现为直接报模块找不到。验证 DataSet 请求。上面的示例里transport.read.url是/api/users这是一个不存在的接口。所以你会看到 Table 显示“加载失败”或空数据但 Network 面板里应该能看到一条对/api/users的请求。如果请求根本没发出说明autoQuery: true没生效或者 DataSet 没有正确绑定到 Table。为了看到成功结果你可以临时把transport改成 mock 数据const dataSet new DataSet({ autoQuery: true, fields: [ { name: name, type: string, label: 姓名 }, { name: age, type: number, label: 年龄 }, { name: dept, type: string, label: 部门 }, ], data: [ { name: 张三, age: 28, dept: 前端组 }, { name: 李四, age: 32, dept: 后端组 }, { name: 王五, age: 26, dept: 测试组 }, ], });刷新页面Table 应该显示三行数据。点击“刷新数据”按钮如果 DataSet 没有配置transport按钮不会发请求但数据仍然在。这说明 DataSet 的本地数据模式是正常的。验证主题变量。打开浏览器开发者工具选中一个 Button在 Elements 面板里看它的background-color。如果你在theme.css里把--c7n-primary-color改成了#2f54eb那么主按钮的背景色应该是这个值而不是默认的蓝色。如果没生效检查theme.css的引入顺序以及变量名是否拼写正确。Choerodon UI 的 CSS 变量前缀是--c7n-不是--choerodon-。验证按需引入。在 Vite 的构建输出里如果你只用了 Button 和 Table最终 bundle 不应该包含全部 90 组件。运行pnpm build看dist/assets下的 JS 文件大小。如果按需引入生效主 chunk 应该在几百 KB 级别如果全量引入会超过 1MB。Choerodon UI 的 ES 模块天然支持 tree-shaking但前提是你用import { Button } from choerodon-ui/pro这种命名导入而不是import ChoerodonUI from choerodon-ui然后ChoerodonUI.Button。还有一个细节choerodon-ui/pro和choerodon-ui是两个入口。pro入口包含 DataSet 和高级组件体积更大基础入口只有纯 UI 组件。如果你不用 DataSet从choerodon-ui导入可以进一步减小体积。5. 接入常见报错与排查对照这一节整理我在接入 Choerodon UI 时真实遇到过的报错以及对应的排查路径。每个报错都给出错误信息、原因和解决方式。第一个报错Module not found: Cant resolve choerodon-ui/es/button。这个通常出现在 Webpack 项目里原因是 Webpack 没有正确解析 ES 模块的路径。解决方式是在resolve.extensions里加上.js和.ts或者直接用choerodon-ui/lib/button走 CommonJS 入口。Vite 项目一般不会遇到因为 Vite 默认支持 ES 模块。第二个报错Cannot read property query of undefined。这个报错说明 DataSet 没有正确创建或者 Table 的dataSet属性传入了 undefined。检查new DataSet()是否在组件外部创建。如果在组件内部创建每次渲染都会 new 一个新的 DataSet导致状态丢失。正确做法是把 DataSet 定义在组件外部或者用useMemo包裹。第三个报错local proxy failed或401 Unauthorized。这个不是 Choerodon UI 本身的错而是 DataSet 请求接口时认证失败。Choerodon UI 的 DataSet 支持在transport里配置headers但更推荐的做法是全局配置 axios 拦截器。如果你用 fetch需要在transport.read里手动加headerstransport: { read: { url: /api/users, method: get, headers: { Authorization: Bearer ${token}, }, }, },第四个报错reading choices。这个报错通常出现在 LOVList of Value组件里原因是 DataSet 的lookupUrl没有配置或者返回的数据结构不符合 Choerodon UI 的预期。LOV 要求接口返回{ content: [], totalElements: 0 }这种分页结构。如果你的后端返回的是裸数组需要在transport.read里用transformResponse转换。第五个报错OAuth token expired。这个和 Choerodon UI 无关是认证层的问题。但如果你在 DataSet 的feedback里配置了loadFailed回调可以在这里统一处理 token 过期跳转登录。第六个报错主题变量不生效。排查顺序是先确认theme.css在choerodon-ui.css之后引入再确认变量名是--c7n-前缀最后确认没有在组件内联样式里写死颜色。内联样式优先级高于 CSS 变量会覆盖主题。第七个报错DataSet is not a constructor。这个通常是因为导入路径写成了import { DataSet } from choerodon-ui而 DataSet 只在choerodon-ui/pro里导出。改成import { DataSet } from choerodon-ui/pro即可。如果你在接入过程中遇到其他报错可以先查 Choerodon UI 的官方文档里面有完整的 API 说明和示例。文档地址在官网的“文档”页签下。另外Choerodon UI 是开源项目GitHub 上有 issue 区搜索报错关键词通常能找到类似问题。6. 从评估到落地的下一步Choerodon UI 的接入成本比想象中低。一个 React 项目从零到跑通第一个 DataSet 驱动的表格熟练的话半小时以内。真正需要花时间的是理解 DataSet 的数据流它把“数据获取、字段校验、分页排序、值变化监听”这些原本散落在组件里的逻辑收敛到了一个独立的数据源对象里。组件只负责渲染DataSet 负责状态。这个模式一旦习惯中后台页面的代码量会明显下降。如果你打算在团队内推广建议先做一个“最小可行接入”选一个中等复杂度的列表页用 Choerodon UI 重写对比一下代码行数和联调时间。我试过的一个场景是带查询表单、分页、行内编辑的表格用传统方式写了 400 多行用 DataSet Table 之后降到 150 行左右而且校验逻辑不用重复写。主题定制方面CSS 变量覆盖是最稳妥的方案。不要直接改node_modules里的 Less 文件升级时会丢。如果品牌色需要动态切换用ConfigProvider包一层把主题变量通过 context 注入。最后提醒一点Choerodon UI 的组件虽然多但不要为了用而用。它的优势在中后台的复杂数据场景比如 LOV、Attachment、DataSet 表单。如果你的页面只是几个静态展示用原生 HTML 或者轻量组件就够了。工具选型的原则始终是——让复杂的事情变简单而不是让简单的事情变复杂。如果你在接入过程中需要查 API 或者找示例可以直接访问 Choerodon UI 的模型对话页面把报错信息贴进去通常能得到针对性的排查建议。对于长期做中后台编码的团队也可以了解一下 Coding Plan它在 DataSet 的模板代码生成和组件属性补全上有一些提效的玩法。