Pro React Admin: 统一工程底座,承载多种应用...

Pro React Admin v5 架构解析:从项目构建到一次受权限保护的数据请求

一个后台应用刚开始可能只有一个入口。随着业务增加,团队会希望把演示页面和正式管理页面分开,把不同客户的前端独立构建,让通知或管理能力能按需组合,还要让同一套组件可以单独预览。此时最值得先回答的问题是:哪些东西应该复用,哪些东西应该隔离,以及这些选择应该发生在什么时候?

Pro React Admin v5 把这些问题落到了代码结构和构建流程里。本文沿着一个具体过程展开:构建系统如何选中企业入口,应用如何组装用户管理模块,一次列表请求如何经过权限和数据 Provider,最终到达可选的企业 API。

先把架构看成三个选择时点

项目把变化拆成三类,并在各自合适的时点处理:

  1. 构建时选择项目 :从 default、enterprise、独立项目或微前端 Shell 中选一个入口,生成对应产物。
  2. 应用启动时选择模块:决定当前入口包含哪些业务能力,并据此组装路由、Provider 和页面插槽。
  3. 请求发生时选择数据实现:页面使用稳定的 Provider 契约,底层可以连接演示数据,也可以连接 REST 服务。
text 复制代码
src/projects/registry.json + config/project-registry.mjs
                         │
                  项目 CLI / Webpack
                         │ 构建时选择入口和产物
       ┌─────────────────┼──────────────────────┐
     default          enterprise        projectA / projectB / shell
       └─────────────────┴──────────────────────┘
                         │
                    app/bootstrap
              ┌──────────┴──────────┐
         应用壳与生命周期        项目模块清单
       Store / Layout / Tabs    routes / Provider / 插槽
                                  │
                           features/* 页面
                                  │
                 platform 权限 / DataProvider / 请求
                       ┌──────────┴──────────┐
                    演示 Provider        REST Provider
                                            │
                                  Express → 业务服务 → SQLite

       shared:跨业务 UI 与工具       packages/wui-react:独立 UI 包
       Shell / Remote:由 Module Federation 单独连接

这些目录对应明确的依赖方向:业务页面依赖平台提供的契约,平台不反向依赖具体页面;通用 UI 不依赖业务,独立组件包也不导入应用源码。导入边界和路由契约检查会持续约束这些关系,让层与层之间的依赖保持清楚。

接下来就沿着用户管理页从构建到取数的过程,展开这三层选择。

第一步:构建系统选择一个项目入口

项目清单位于 src/projects/registry.json,登记入口、路由、输出目录和 Remote 配置;config/project-registry.mjs 负责统一解析项目并生成构建计划。Webpack、开发命令、预览、清理、脚手架和部署组合都读取同一份解析结果,项目配置和产物定位保持一致。

当前工作区包含完整展示应用 default、精简业务入口 enterprise、普通独立项目 projectA 和 projectB,以及用于加载 Remote 的 shell。PROJECT 在构建时决定所选项目,每个入口因此拥有自己的路由和产物;运行时应用只加载目标项目。

新增项目时,可以先让脚手架展示计划,再生成入口文件:

bash 复制代码
pnpm run project:create customer --dry-run
pnpm run project:create customer
pnpm run project:dev customer

脚手架创建 entry、首页和 router,并同步项目注册信息;创建 Remote 时还会生成暴露组件和本地 Provider。新入口复用已有应用装配与平台服务,但正式业务仍需明确加入认证和页面权限。

第二步:应用启动时组装业务模块

选定入口后,app/bootstrap 创建 React root,装配布局、路由、Store 和业务 Provider。页面放在 src/features/<name>,按领域组织 routes、API、model 和 hooks。一个 feature 通过模块契约告诉应用它提供什么:

ts 复制代码
export const administrationModule: ApplicationModule = {
  id: 'administration',
  contractVersion: 1,
  routes: administrationRoutes,
  resources: administrationResources,
  Provider: AdministrationProvider,
}

应用模块清单选中需要的 feature 后,注册表会验证模块版本、依赖、重复路由和权限策略,再按依赖顺序组装 routes 与 Provider。组织管理和通知已经接入这套机制:default 选择两者,enterprise 只选择组织管理。公共 Header 通过模块插槽呈现通知入口,因此企业入口没有启用通知时,不需要让 Header 再判断项目名称。

这是一套编译期声明、启动时装配的模块机制。新增业务可以按相同契约接入;目前的可组合点发生在构建和应用启动阶段,运行期插件下载、动态重建路由和插件版本协商尚未实现。

路由结构与权限策略分开维护

页面组件和路由模块负责表达"有哪些页面";config/route-policy.json 负责页面标题、翻译键、菜单层级、排序、图标和权限。导航树根据当前项目实际注册的路由和当前用户权限生成,所以一个页面没有注册到企业入口时,不会只因为共享了 Layout 就出现在企业菜单里。

权限状态由 PermissionService 按身份维护,并通过订阅快照通知路由守卫、菜单和按钮。登录状态变化、权限同步或撤权后,界面使用同一份最新快照更新。前端负责按权限呈现交互,真实 API 则在服务端重新验证当前用户和角色,两者共同形成访问控制。

第三步:每个应用根拥有自己的状态和生命周期

每个应用根都会创建独立的 Zustand Store 和业务 Provider 树。壳 Store 只保存侧栏偏好,按 projectId 命名;业务数据和登录身份不会混进这个持久化状态。这样同一页面被两个 Remote 同时挂载时,它们的业务状态也不会因为共享模块文件而变成一个全局单例。

Tabs 背后的 KeepAliveProvider 缓存当前应用根里的页面实例,最多保留 5 个非持久页面,采用 LRU 淘汰旧页;它用于保留短暂离开页面时的表单草稿,不承担长期数据存储。这个页面缓存与后面提到的服务端数据缓存是两件不同的事。

用户切换账号或租户时,SessionScope 会销毁旧页面树、Tabs、KeepAlive 和业务 Provider,再创建新的工作区。权限和资源缓存也绑定当前会话,旧请求即使晚到,也不能把之前身份的数据重新写回当前缓存。这样前一个工作区的页面状态和业务数据不会带入新的身份上下文。目前一个 origin 共享一个活动身份;多身份并行需要独立 origin 或扩展会话模型。

第四步:页面通过 Provider 读取和修改数据

以用户列表为例,页面通过 administration feature 的 DataProvider 发起数据操作。platform/data/provider.ts 定义了分页列表、单条读取、创建、更新、删除和取消请求等操作;资源定义提供路径、响应 parser 和只读标记。REST adapter 复用平台请求层,会处理会话凭据、错误和 AbortSignal;领域 parser 再验证服务端返回的数据形状。

把这条路径落到实际代码上:/administration/users 由管理模块注册,路由策略要求 user:read。页面加载列表时调用 Provider 的 list('users', query, options);资源定义将 users 映射到 /api/admin/users 并指定 parseUser。REST 模式会发送带会话凭据的请求,企业 API 再按当前用户权限和租户范围读取数据;演示模式则从应用实例的内存数据读取。两种模式共用页面的查询、分页和展示逻辑。

演示数据刷新后会重置。真实 REST 服务可以使用仓库附带的企业 API,也可以替换成团队已有的业务服务。

对于服务器数据,平台还提供会话级内存缓存:有效期 15 秒、最多 100 项;相同查询可以共享一次请求,但不同消费者可以分别取消。成功写入会清理相关列表和审计数据;身份变化或缓存失效后的迟到响应不会重新填充缓存。缓存限于浏览器内存,目前没有后台刷新、实时订阅或分布式缓存。

从职责上看,页面关心领域记录和交互,feature 关心数据解析与业务动作,platform 关心通用传输、错误、取消和缓存。这种分层使替换 API 时通常不必重写页面。

可选企业 API:授权在服务端落地

仓库附带的 api/enterprise 是可选后端,使用 Node 24 原生 TypeScript、Express 和 SQLite,适合单实例自托管。它把 HTTP adapter、业务授权与会话、SQLite 存储分开组织。

真实请求的大致路径是:浏览器发送 Bearer 会话,服务端查找有效会话和用户,读取当前角色权限,再按该会话所属的 tenant_id 访问业务记录。租户由服务端会话确定,不由请求 Header 选择;每次请求都会重新读取用户与角色状态,不缓存授权结论。密码使用带随机盐的 scrypt,随机会话 token 只在登录时返回,数据库保存其 SHA-256 摘要。

用户、角色或会话发生写入时,业务修改、会话撤销和审计记录在同一 SQLite 事务中提交;审计 API 为只读,数据库触发器拒绝更新和删除。这让失败的审计写入也能回滚对应业务操作。拥有数据库文件权限的管理员仍可直接修改文件,因此审计日志不满足 WORM 或外部合规归档要求。

后端当前覆盖租户隔离、RBAC、用户与角色持久化、会话撤销和事务审计。生产接入仍需结合实际环境设计 OIDC/SSO、多组织成员关系、数据库迁移、备份恢复和多实例扩容。

Module Federation:远程部署仍需要明确协议

shell 是 Host,projectA 和 projectB 是 Remote。它们既可以分别启动开发,也可以构建成独立 Remote,再由 Shell 加载。Host 在注入 remoteEntry.js 前会先读取同目录 remote-manifest.json,检查 schema、协议版本、Remote 名称和共享依赖;加载失败会重试,最终显示 fallback。

跨应用状态通过版本化 Bridge 明确传递;React 等 shared singleton 用于依赖复用,身份和授权仍由当前会话与服务端完成。样式和权限隔离由应用部署边界承担;不可信的 Remote 应放在独立 origin 或 iframe 中。Module Federation 处理 Remote 的构建和加载,部署时仍需单独设计信任边界。

组件预览与交付

packages/wui-react 是可单独构建的 UI 包,输出 ESM、CJS、CSS 和 TypeScript 声明,不依赖应用源码。Storybook 从当前源码读取组件示例;公共包组件、共享 UI 和应用 UI 入口合计有 157 个直接预览入口。

构建流水线按 default、enterprise、Storybook、组件包和微前端组合分别处理产物。GitHub Pages 提供应用入口导航和 Storybook 预览;应用也支持 Vercel 和 Nginx 静态部署。部署组合根据项目注册信息放置 Shell 和 Remote,HTML、manifest 和 Remote entry 及时更新,带内容 hash 的静态资源可以长期缓存。

跑起来,再按需要深入

要求 Node.js >=24.15.0 <25 和 pnpm 11.5.2。克隆仓库后,在根目录安装并启动完整展示应用:

bash 复制代码
git clone https://github.com/wkylin/pro-react-admin.git
cd pro-react-admin
pnpm install --frozen-lockfile
pnpm start

浏览器打开 http://localhost:8080/#/signin。想单独体验精简企业入口,可以停止当前服务并运行:

bash 复制代码
pnpm run start:enterprise

若想看 Host/Remote 的实际协作,可分别在三个终端运行 pnpm run start:mf:projectA、pnpm run start:mf:projectB 和 pnpm run start:mf:shell,再打开 http://localhost:8080/#/portal。这些演示使用公开示例,不需要真实数据库。要运行持久化 API,则需要另外配置环境并显式初始化租户。

最后回到最初的问题

这套架构的组织方式可以概括为:项目注册表处理"要构建哪个应用",模块契约处理"这个应用包含哪些业务能力",Provider 处理"这些页面从哪里读写数据"。路由策略和服务端授权规定"当前身份能访问什么";Store、Provider 和缓存的生命周期则规定"状态属于哪个应用根和哪个会话"。

当变化发生在入口层,就新增项目配置;当变化发生在业务能力层,就实现 feature 并加入模块清单;当变化发生在后端服务层,就替换 Provider adapter。把变化放到清楚的边界里,是 Pro React Admin v5 这次架构整理的核心。

可以从GitHub 仓库查看代码,也可以直接打开在线应用导航、默认应用和Storybook体验。

相关推荐
葡萄城技术团队1 小时前
dsh-spreadjs-editor 当前支持什么:安装前需要了解的几件事
前端
三*一2 小时前
优化修整算法
前端·javascript·算法
weifont3 小时前
自动化抓取和上架商品:能不动手,就少动手
运维·前端·自动化
米柆3 小时前
HTML5 audio /video 完整事件监听模板
前端·html·html5
IT_陈寒3 小时前
Vite热更新失效?你可能也踩了这个坑
前端·人工智能·后端
程序员大阳4 小时前
副队长CSS教程(30)–CSS Grid 实战:实现复杂自适应表单布局
前端·css·自适应·grid·表单
Csvn4 小时前
微前端实现
前端
Chrischaan5 小时前
做 AI 塔罗小程序时,我为什么不让大模型自己抽牌:一次上线复盘
前端
骑着蜗牛撵大象3275 小时前
LangChain 工具调用从声明到闭环:给智能体接上真实的手脚
前端