概述
OpenPLC Editor 是一款跨平台桌面 IDE,用于使用 IEC 61131-3 标准语言(结构化文本、梯形图、功能块图和指令表)以及 Python 和 C++ 扩展对 PLC(可编程逻辑控制器)进行编程。它基于 Electron 和 React 构建,提供了从编写到部署的完整工作流:创建项目、使用多种 PLC 语言编写程序、编译为原生固件、通过 Modbus 或 WebSocket 调试实时变量,以及上传至物理硬件或内置 AVR 模拟器。
OpenPLC Editor 的功能
OpenPLC Editor 的核心在于弥合 IEC 61131-3 编程与真实工业硬件之间的鸿沟。开发者可以使用内置编辑器编写 PLC 程序——基于文本的编辑器(由 Monaco 驱动的代码编辑器,支持 ST、IL、Python、C++)或图形化编辑器(支持拖拽梯级的梯形图,以及基于流图画布的功能块图和 SFC)——而编辑器会处理其余工作:将项目序列化为 XML,通过多阶段流水线编译生成 C 代码及特定平台固件,为数十种受支持的硬件目标提供具备板级感知的引脚映射,以及提供用于读写 PLC 实时变量的完整调试协议。
下表概述了核心功能:
| 功能 | 描述 |
|---|---|
| IEC 61131-3 编辑 | 结构化文本 (ST)、指令表 (IL)、梯形图 (LD)、功能块图 (FBD)、顺序功能图 (SFC) |
| 扩展语言 | Python 和 C++ 程序编辑,支持 Monaco + LSP |
| 编译流水线 | XML → 结构化文本 → C 代码 → 固件 (Arduino CLI / OpenPLC 编译器) |
| 硬件目标 | Arduino、Raspberry Pi、ESP32 及通过可配置引脚映射支持的工业主板 |
| 实时调试 | 通过 Modbus TCP、Modbus RTU、WebSocket 或虚拟串口进行变量读写 |
| 内置模拟器 | AVR8JS ATmega2560 模拟器——无需硬件即可进行测试 |
| EtherCAT 支持 | ESI 设备库,扫描、验证和配置 EtherCAT 网络 |
| 工业协议 | Modbus TCP/RTU 配置,OPC UA 服务器,S7Comm 服务器 |
| 跨平台 | macOS、Windows、Linux——支持 x64 和 ARM64 架构 |
| 国际化 | 基于 i18next 的多语言支持 |
架构一览
OpenPLC Editor 遵循端口与适配器(六边形)架构,将 React 前端与 Electron 主进程严格分离。前端绝不直接导入后端或 Electron API——所有跨边界通信均通过由特定平台适配器实现的类型化端口接口进行。这种设计使得相同的 UI 代码库既能运行在 Electron 桌面编辑器中,也能运行在基于浏览器 的 Web 应用中,各自提供对应的适配器实现(Electron IPC 对比 HTTP/WebRTC)。
下图展示了高层级的数据流和各层关系:

项目结构
代码库被组织为清晰的架构层,每一层都遵循强制依赖规则(由 npm run validate:arch 验证)。下方的树状图展示了顶层源码布局及各目录的用途:
Copy code
src/
├── main/ │ ├── main.ts # BrowserWindow 生命周期,应用引导
│ ├── menu.ts # 应用菜单配置
│ └── modules/ # IPC 桥接,预加载,存储
│
├── frontend/ # React 渲染进程 (UI 层)
│ ├── components/ # Atomic Design: _atoms → _molecules → _organisms → _features → _templates
│ ├── store/ # Zustand 存储 (17 个基于 Immer 的可组合切片)
│ ├── hooks/ # 自定义 React Hooks
│ ├── services/ # 业务逻辑与副作用编排
│ ├── screens/ # 顶层屏幕 (StartScreen, WorkspaceScreen)
│ ├── data/ # 静态数据 (功能块库,主板定义)
│ ├── utils/ # 领域工具 (PLC,图形,调试,格式化)
│ ├── locales/ # i18next 翻译文件
│ └── assets/ # 图片,图标,样式
│
├── backend/ # 主进程模块 (Node.js)
│ ├── editor/ # 编译器,硬件,Modbus,WebSocket,服务
│ └── shared/ # 平台无关逻辑 (XML 生成,模拟器,EtherCAT)
│
├── middleware/ # 端口与适配器层 (桥接层)
│ ├── shared/ports/ # 端口接口 (平台无关契约)
│ ├── shared/providers/ # PlatformProvider (用于依赖注入的 React Context)
│ └── adapters/editor/ # Electron 特定的适配器实现
│
└── types/ # 共享的 TypeScript 类型契约 (IPC, PLC)
各层如何通信
应用程序在两个 Electron 进程中运行,并遵循严格的通信契约:
| 方面 | 渲染进程 | 主进程 |
|---|---|---|
| 运行时 | Chromium (React 18) | Node.js |
| 访问权限 | UI 渲染,状态,用户交互 | 文件系统,串口,编译,网络 |
| 状态 | Zustand 存储 (17 个切片) | Electron-store (窗口边界,用户设置) |
| 桥接 | 通过预加载的 contextBridge 使用 window.bridge.* | ipcMain.handle()——50+ 个已注册通道 |
| 入口 | src/main.tsx → App.tsx | src/main/main.ts → MainProcessBridge |
渲染进程绝不直接调用 Node.js API。相反,组件使用端口 Hooks(例如 useCompiler()、useProject()),这些 Hooks 会解析为调用 window.bridge.* 方法的适配器实现。这些方法由预加载脚本通过 Electron 的 contextBridge 暴露,并在主进程中由 MainProcessBridge 处理。这种间接设计并非偶然——它是使相同的 React 组件树能够借助基于 HTTP 的适配器(而非 IPC)在 Web 浏览器中运行的基础。
平台双重性:编辑器与 Web
一个独特的架构特性是 PlatformCapabilities 系统——这是一组功能开关,允许共享 UI 根据宿主平台有条件地渲染或启用特定功能。Electron 编辑器和 Web 应用有着根本不同的能力配置:
| 功能 | 编辑器 (Electron) | Web (浏览器) |
|---|---|---|
| 原生文件对话框 | ✅ | ❌ |
| 本地串口 | ✅ | ❌ |
| 需要身份验证 | ❌ | ✅ |
| Orchestrator 设备集群 | ❌ | ✅ |
| WebRTC 连接 | ❌ | ✅ |
| 本地文件系统项目 | ✅ | ❌ |
| Python LSP | ✅ | ❌ |
| 版本控制 | ❌ | ✅ |
| AI 助手 | ❌ | ✅ |
| EtherCAT 配置 | ✅ | ❌ |
| 进程内模拟器 | ✅ | ✅ |
组件通过 useCapabilities() 检查这些标志,而不是直接探测平台,从而保持 UI 代码与部署上下文解耦。
核心架构模式
代码库中反复出现三种模式,在深入了解之前理解它们至关重要:
1. 端口与适配器(依赖倒置) —— src/middleware/shared/ports/ 中的端口接口定义了 UI 的需求。src/middleware/adapters/editor/ 中的编辑器适配器使用 window.bridge.* 实现这些接口。PlatformProvider React Context 在应用根部将所有内容连接在一起。这意味着任何组件都可以使用模拟端口进行测试,且整个 UI 层可移植到非 Electron 环境中。
2. Zustand 存储组合 —— 单一的 Zustand 存储由 17 个独立的切片组合而成(src/frontend/store/slices/),每个切片遵循三文件模式:types.ts(状态形状 + 操作签名)、slice.ts(使用 Immer 的 produce() 实现)和 index.ts(重新导出)。切片在 createOpenPLCStore() 中合并,并通过自动生成的选择器 Hooks 访问,以实现最佳的重新渲染性能。
3. 原子设计组件 —— UI 遵循原子设计方法论,分为五个层级:_atoms(按钮、输入框)、_molecules(选项卡、模态框、表格)、_organisms(资源管理器、调试器、控制台)、_features(特定上下文的捆绑,如工作区编辑器)和 _templates(布局包装器)。导航由 Zustand 的 tabs 和 editor 切片通过选项卡驱动——没有基于 URL 的路由。
快速上手
前置条件
开始之前,请确保你的系统满足这些硬性要求。项目在执行 npm install 期间会强制进行引擎版本检查,因此版本不匹配将直接导致失败。
| 需求 | 版本 | 原因 |
|---|---|---|
| Git | 最新稳定版 | 用于克隆代码库 |
| Node.js | ≥ 20.x, < 24.x | 兼容 Electron 35 及原生模块 |
| npm | ≥ 10.x | 包管理器(不支持 pnpm/yarn) |
| 网络访问 | 必需 | 安装期间需从 GitHub Releases 下载二进制文件 |
用于开发和分发的支持平台:
| 平台 | 架构 | 安装包格式 |
|---|---|---|
| macOS | x64, ARM64 (Apple Silicon) | DMG |
| Windows | x64 | NSIS |
| Linux | x64 | AppImage |
克隆并安装
安装过程不仅会拉取 npm 包,还会下载编辑器在运行时依赖的 PLC 编译器工具链(xml2st 和 matiec 二进制文件)。

详细步骤:
git clone https://github.com/Autonomy-Logic/openplc-editor.gitcd openplc-editor # 2. 安装依赖(这会触发 postinstall 链)npm install
postinstall 脚本链会自动执行以下四项操作 package.json:
download-binaries.ts— 从 GitHub Releases 下载xml2st(v4.0.3)和matiec(v4.0.11)到resources/bin/<platform>/<arch>/。这些是你在编译 PLC 项目时编辑器调用的 IEC 61131-3 编译工具。check-native-dep.js— 验证没有原生 Node.js 模块泄漏到根目录的node_modules中(它们必须存放在release/app/目录下)。electron-builder install-app-deps— 根据正确的 Electron 版本重构原生 Electron 插件(例如serialport)。build:dll— 创建 Webpack DLL 缓存以加速开发环境的重新构建。
如果因网络问题导致二进制文件下载失败,你可以单独重新运行此步骤:
npm run setup:binaries
启动开发环境
只需一条命令,即可在开发模式下启动完整的 Electron 应用,并支持主进程和渲染进程的热重载:
npm run dev
该命令的执行流程如下:

| 进程 | 运行内容 | 热重载 |
|---|---|---|
| 渲染进程 | 运行在 localhost:1313 的 Webpack Dev Server — 提供 React UI 服务 | 是 (React Refresh / HMR) |
| 主进程 | 通过 electronmon 运行 Electron — 监听 src/main/** | 是 (自动重启 Electron) |
| 预加载脚本 | 通过 webpack.config.preload.dev.ts 单独编译 | 需手动重新构建 |
首次启动时,你会看到一个启动画面(580×366px),随后是起始屏幕——即未加载项目时显示的着
启动时发生了什么
了解引导序列有助于你在调试或扩展编辑器时理清头绪。应用程序遵循清晰的分层初始化流程:
陆视图。当你创建或打开一个项目后,UI 将过渡到包含完整 IDE 的工作区屏幕。

按顺序排列的关键初始化步骤:
- 主进程创建
BrowserWindow,将ProjectService、PouService、CompilerModule和HardwareModule初始化为单例,然后将它们接入注册了所有 IPC 处理程序的MainProcessBridge中。 - 预加载脚本通过 Electron 的
contextBridge暴露window.bridge.*—— 这是渲染进程与主进程通信的唯一路径。 - React 根组件(
App.tsx)初始化 Zustand store,加载系统功能块库,并使用editorPorts配置将所有内容包裹在PlatformProvider中。 - 屏幕路由完全由 store 状态驱动 —— 如果
project.meta.path为空,则渲染起始屏幕;否则显示工作区屏幕。此处没有基于 URL 的路由。
项目结构概览
源代码被组织成具有强制依赖规则的不同架构层(运行 npm run validate:arch 以进行检查):
src/
├── main/ # Electron 主进程 (Node.js)
│ ├── main.ts # 应用引导,窗口创建
│ ├── menu.ts # 原生菜单构建器
│ └── modules/ # IPC 桥接,预加载,Store
├── frontend/ # React UI 层 (渲染进程)
│ ├── components/ # 原子设计: _atoms → _molecules → _organisms → _features → _templates
│ ├── store/ # Zustand store (19 个组合切片)
│ ├── hooks/ # 自定义 React hooks
│ ├── services/ # 业务逻辑与副作用
│ ├── screens/ # 顶层屏幕组件
│ ├── utils/ # 领域工具
│ ├── data/ # 静态数据 (功能块库)
│ └── locales/ # i18next 翻译
├── backend/
│ ├── editor/ # 主进程模块 (编译器,硬件,服务)
│ └── shared/ # 平台无关逻辑 (XML 生成,解析,模拟器)
├── middleware/ # 端口与适配器层 (依赖倒置)
│ ├── shared/ports/ # 端口接口 (平台无关契约)
│ ├── shared/providers/ # PlatformContext (React Context + DI)
│ └── adapters/editor/ # Electron 特定的端口实现
└── types/ # 共享的 IPC 与 PLC 类型契约
端口与适配器模式是架构的基石:前端代码从不直接导入后端或 Electron API。所有特定于平台的行为都通过类型化的端口接口流动,并在应用根部通过 PlatformProvider 进行连接。这意味着只需交换适配器实现,同一个前端就可以运行在不同的后端(Electron vs. Web)上。
技术栈
运行时与语言基础
在底层,编辑器运行于 Electron v35 之上,该版本为 UI 提供了 Chromium 渲染引擎,并为系统级操作提供了 Node.js 运行时。整个代码库使用 TypeScript 5.4 编写,并启用了严格模式,编译器输出和 lib 环境均目标设定为 ES2022。这种组合使项目能够访问现代 JavaScript 特性(如顶层 await、私有类字段、structuredClone),同时在主进程、渲染进程和共享中间件层之间保持类型安全。
Node.js 引擎版本要求为 ≥20.x <24,npm 版本要求为 ≥10.x,以确保项目运行在当前的 LTS 版本线上。TypeScript 配置了 esModuleInterop 和 allowSyntheticDefaultImports,旨在与 Electron 和 Webpack 所依赖的庞大 CommonJS 包生态系统实现平滑互操作。
进程架构
Electron 应用本质上采用多进程架构,OpenPLC 编辑器通过清晰的职责分离践行了这一点。主进程 (src/main/main.ts) 是 Node.js 进程,负责拥有 BrowserWindow、管理原生菜单、处理 IPC,以及协调编译器和硬件模块等后端服务。渲染进程 (src/main.tsx) 是由 Chromium 托管的 React 应用,负责渲染整个 UI。预加载脚本 连接了这两个世界,通过 Electron 的上下文桥接,向渲染进程暴露了经过严格作用域限定的 window.bridge API。
┌──────────────────────────────────────────────────────────────┐
│ OpenPLC Editor 进程模型 │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 主进程 (Node.js) │ │
│ │ ───────────────────── │ │
│ │ • BrowserWindow 生命周期 │ │
│ │ • IPC 处理器 (MainProcessBridge) │ │
│ │ • 后端: 编译器, 硬件, 服务 │ │
│ │ • 自动更新器 (electron-updater) │ │
│ │ • 持久化存储 (electron-store) │ │
│ └─────────────┬──────────────────────────┬────────────┘ │
│ │ IPC (ipcMain ↔ ipcRender)│ │
│ ┌─────────────▼──────────────────────────▼────────────┐ │
│ │ 预加载脚本 (沙盒化) │ │
│ │ ───────────────────── │ │
│ │ • contextBridge.exposeInMainWorld('bridge', ...) │ │
│ │ • 作用域 API 接口 — 无完整 Node 访问权限 │ │
│ └─────────────┬──────────────────────────────────────┘ │
│ │ window.bridge.* │
│ ┌─────────────▼──────────────────────────────────────┐ │
│ │ 渲染进程 (Chromium + React 18) │ │
│ │ ───────────────────── │ │
│ │ • React 组件树 (App → Screens) │ │
│ │ • Zustand 存储 (16 个切片) │ │
│ │ • Monaco / XYFlow 编辑器 │ │
│ │ • Radix UI + Tailwind CSS │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
前端框架与 UI
渲染进程是一个 React 18 应用,使用了支持并发渲染的现代 createRoot API。组件架构遵循原子设计 (Atomic Design) 原则,在 src/frontend/components/ 目录下组织为四个层级:
| 层级 | 目录 | 用途 | 示例 |
|---|---|---|---|
| 原子 | _atoms/ | 最小的可复用基元 | 按钮、输入框、复选框、选项卡 |
| 分子 | _molecules/ | 由原子组合而成,具有领域感知 | 面包屑、库树、变量表 |
| 有机体 | _organisms/ | 完整的功能区块 | 调试器、资源管理器、控制台、变量编辑器 |
| 模板 | _templates/ | 页面级布局组合 | AppLayout、WorkspaceLayout、EditorLayout |
组件库与样式
UI 构建在 Radix UI 基元之上——这些是无样式、可访问的无头组件,项目使用 Tailwind CSS 3 和 class-variance-authority (CVA) 对其进行样式定制。这种组合在保留无障碍访问性的同时,赋予了完全的设计控制权。项目使用的 Radix 基元包括 Accordion、Dialog、Dropdown Menu、Popover、Select、Tabs、Toast、Tooltip 等。Lucide React 和 Radix Icons 提供了图标集。
Tailwind 配置了自定义设计令牌系统:brand 调色板使用 CSS 自定义属性(从 --primary-light 到 --primary-dark)来实现运行时主题切换,自定义字体系列(用于展示的 Poppins,用于说明文本的 Inter)保持了工业 IDE 的视觉美学。暗模式采用基于类名的策略(darkMode: 'class')。
状态管理
应用状态由 Zustand 5 结合切片组合模式进行管理。根状态并非采用单一庞大的存储,而是由 16 个独立的切片组装而成,每个切片定义了各自的状态形状和操作:
| 切片 | 领域 | 核心职责 |
|---|---|---|
| Project | 项目生命周期 | 创建、打开、保存、POU 管理 |
| Editor | 编辑状态 | 活动编辑器、选择、光标 |
| Tabs | 选项卡导航 | 打开/关闭/聚焦选项卡管理 |
| Device | 硬件配置 | 主板选择、引脚映射、Modbus |
| Ladder | LD 编辑器 | 梯形图节点与连接 |
| FBD | FBD 编辑器 | 功能块图流状态 |
| Library | 函数库 | 系统/用户功能块和函数 |
| Console | 日志 | 日志输出与过滤 |
| Search | 搜索 | 全项目搜索与替换 |
| History | 撤销/重做 | 编辑历史栈 |
| Workspace | 工作区布局 | 面板尺寸与可见性 |
| File | 文件操作 | 文件系统交互 |
| Modal | 对话框管理 | 模态框开启/关闭状态 |
| VersionControl | 版本跟踪 | 项目版本状态 |
| WebRTC | 实时通信 | 对等连接状态 |
| AI | AI 功能 | AI 辅助编程配置 |
Zustand 引入 Immer(通过 enableMapSet())以可变语法实现不可变状态更新,并使用 subscribeWithSelector 中间件实现细粒度响应性。auto-zustand-selectors-hook 包通过自动生成的选择器钩子封装了存储,防止组件仅需要部分状态时引发不必要的重新渲染。
编辑器集成
OpenPLC 编辑器支持全部五种 IEC 61131-3 编程语言,每种语言类型采用专门的编辑技术:
| 语言 | 编辑器技术 | 包 | 描述 |
|---|---|---|---|
| 结构化文本 (ST) | Monaco Editor | monaco-editor + @monaco-editor/react | 支持语法高亮、自动补全的完整代码编辑器 |
| 指令表 (IL) | Monaco Editor | monaco-editor | 支持 PLC 语言的文本编辑器 |
| 梯形图 (LD) | 自定义画布编辑器 | react-draggable + 自定义渲染 | 触点/线圈可视化编程 |
| 功能块图 (FBD) | React Flow | @xyflow/react v12 | 基于节点的图编辑器 |
| 顺序功能图 (SFC) | React Flow | @xyflow/react v12 | 步骤/转换图编辑器 |
Monaco Editor (v0.54) 与驱动 VS Code 的编辑器引擎相同,通过 @monaco-editor/react 集成,并使用 monaco-editor-webpack-plugin 进行优化打包(配置中包含对 Python 语言的支持,以用于 PLC 编译器集成)。React Flow (@xyflow/react v12) 为 FBD 和 SFC 编辑器提供了交互式的节点图画布,并支持针对 PLC 特定视觉元素的自定义节点类型和边渲染。
端口与适配器架构
该代码库中最具特色的架构决策之一是端口与适配器(六边形架构)模式。前端 UI 和存储仅依赖于端口接口——即在 docs/ports/ 中定义的抽象契约——而从不依赖于特定平台的实现。具体的适配器在组合根处通过 PlatformProvider 注入:
┌─────────────────────────────────────────────────────┐
│ 共享 UI 层 │
│ (React 组件, hooks, Zustand 存储) │
│ 仅依赖于 ↓ │
├─────────────────────────────────────────────────────┤
│ 端口接口 (10 个端口) │
│ Compiler · Runtime · Debugger · Simulator │
│ Project · Device · System · Window │
│ Accelerator · Theme │
├────────────────────┬────────────────────────────────┤
│ 编辑器适配器 │ Web 适配器 (未来) │
│ (Electron IPC) │ (HTTP/WebRTC) │
└────────────────────┴────────────────────────────────┘
这十个端口接口定义了 UI 与平台之间的完整边界:CompilerPort 用于 PLC 编译管线,RuntimePort 用于远程 PLC 运行时通信,DebuggerPort 用于调试协议操作,SimulatorPort 用于内置 AVR 模拟器,ProjectPort 用于项目生命周期管理,DevicePort 用于硬件发现,SystemPort 用于平台服务,WindowPort 用于原生窗口管理,AcceleratorPort 用于键盘快捷键,ThemePort 用于主题检测。src/middleware/adapters/editor/ 中的每个适配器通过委托给预加载脚本暴露的 window.bridge.* 方法来实现其端口。
工业与领域特定库
除了标准的 Web 技术栈,编辑器还集成了多个为其工业自动化能力提供动力的领域特定库:
| 库 | 版本 | 用途 |
|---|---|---|
| avr8js | 0.20.0 | 基于 JavaScript 的 AVR 微控制器模拟器——在浏览器中运行编译后的 PLC 代码 |
| fast-xml-parser | ^5.6.0 | 解析 PLC 项目 XML 文件 (IEC 61131-3 格式) |
| xmlbuilder2 | ^3.1.1 | 生成 PLC 项目 XML 以用于保存/导出操作 |
| socket.io-client | ^4.8.1 | 与 OpenPLC 运行时进行实时通信 |
| serialport | ^12.0.0 | 用于主板编程的串口访问 (开发依赖) |
| vscode-languageserver | ^9.0.1 | 用于 ST/IL 智能提示的语言服务器协议 |
| monaco-pyright-lsp | ^0.1.7 | 用于编译器集成的 Python 类型检查 LSP |
avr8js 库尤为引人注目:它是一个用纯 JavaScript 编写的完整 AVR ATmega 模拟器,使编辑器无需外部硬件即可模拟编译后的 PLC 程序。fast-xml-parser / xmlbuilder2 对负责处理 PLC 项目在 IEC 61131-3 工具链中使用的标准 XML 格式的双向序列化。
数据处理与校验
应用中的数据流由一系列精心挑选的库进行管理:
- @tanstack/react-query (v5) 负责处理来自运行时和编译器的异步数据获取的服务器状态管理,支持缓存、后台重新获取和乐观更新。
- react-hook-form (v7) 结合 zod (v3) 与 @hookform/resolvers 提供了类型安全的表单校验——Zod 中的 schema 定义可推断为 TypeScript 类型,并在运行时进行验证。
- axios (v1) 作为 HTTP 客户端,负责与 OpenPLC 运行时进行 REST API 通信。
- i18next (v24) 结合 react-i18next (v15) 提供了国际化基础设施,当前配置以英语作为默认和回退语言。
- immer (v10) 在 Zustand 的不可变存储中启用可变风格的状态更新,并激活了
enableMapSet()以原生支持存储状态中的Map和Set。
构建与打包流水线
构建系统是自定义的 Webpack 5 配置,包含六个专门的配置文件,通过 webpack-merge 进行组合:
| 配置文件 | 目标 | 用途 |
|---|---|---|
webpack.config.base.ts | 共享 | 通用加载器 (ts-loader)、解析配置、外部依赖 |
webpack.config.main.dev.ts | electron-main | 支持 HMR 的开发环境主进程 |
webpack.config.main.prod.ts | electron-main | 生产环境主进程 + 预加载打包、Terser 压缩 |
webpack.config.preload.dev.ts | preload | 开发环境预加载脚本编译 |
webpack.config.renderer.dev.ts | web/electron-renderer | 包含 React Refresh、CSS 模块、Monaco 插件的开发环境渲染进程 |
webpack.config.renderer.prod.ts | web/electron-renderer | 生产环境渲染进程优化 |
webpack.config.renderer.dev.dll.ts | web | 用于加速开发环境重构建的 DLL 打包 |
渲染进程的开发配置目标设定为 ['web', 'electron-renderer'],并包含用于热模块替换的 React Refresh、配合 Tailwind 的 Sass/PostCSS 处理、用于 SVG 转 React 组件的 SVGR,以及用于优化代码编辑器打包的 Monaco Editor Webpack Plugin。生产环境构建使用 TerserPlugin 进行并行压缩,并使用 BundleAnalyzerPlugin 进行包体积检查。
桌面打包由 electron-builder (v26) 处理,具备针对 macOS(支持 arm64/x64 通用构建、强化运行时和公证的 DMG)、Windows(NSIS 安装程序,x64)和 Linux(AppImage,x64)的特定平台配置。外部二进制文件(编译器工具、平台资源)在安装时通过 scripts/download-binaries.ts 下载,并打包至特定平台的 extraResources 目录中。
质量与开发者体验
项目通过分层的工具链强制保障代码质量:
- ESLint 9 搭配
typescript-eslint(recommended-type-checked 配置)、react-hooks插件、react-refresh插件,以及用于确定性导入排序的simple-import-sort - Prettier 3 搭配
prettier-plugin-tailwindcss实现自动类名排序 - Husky + lint-staged —— 预提交钩子对暂存的
.{ts,tsx}文件执行 ESLint 修复和 Prettier 写入 - 通过
npm run validate:arch进行架构验证 ——src/__architecture__/validate.ts中的自定义规则强制执行依赖边界 - cspell.json 用于全代码库的拼写检查
测试策略
测试技术栈在两个层级上运作:
单元测试与集成测试 —— 在 jsdom 环境中结合 ts-jest 使用 Jest 30,使用 @testing-library/react 进行组件测试,使用 @testing-library/jest-dom 进行 DOM 断言。覆盖率阈值强制要求关键路径(存储切片、工具函数、后端共享代码和中间件适配器)实现 100% 的函数/行/语句覆盖。测试配置使用 @root/* 路径别名映射和 identity-obj-proxy 来模拟 CSS 模块。
端到端测试 —— Playwright 针对完全构建并打包的应用运行,验证跨越渲染进程、主进程和预加载桥接的多进程工作流。
技术栈概览
| 层级 | 技术 | 版本 |
|---|---|---|
| 桌面运行时 | Electron | ^35.0.0 |
| 语言 | TypeScript | ^5.4.5 |
| UI 框架 | React | ^18.3.1 |
| 状态管理 | Zustand | ^5.0.5 |
| 不可变更新 | Immer | ^10.1.1 |
| 组件基元 | Radix UI | 多个包 |
| 样式 | Tailwind CSS | ^3.4.19 |
| 变体系统 | class-variance-authority | ^0.7.0 |
| 代码编辑器 | Monaco Editor | ^0.54.0 |
| 图编辑器 | @xyflow/react | ^12.0.1 |
| 服务端状态 | @tanstack/react-query | ^5.90.21 |
| 表单校验 | react-hook-form + zod | ^7.66.0 / ^3.25.67 |
| XML 处理 | fast-xml-parser + xmlbuilder2 | ^5.6.0 / ^3.1.1 |
| 仿真 | avr8js | 0.20.0 |
| 实时通信 | socket.io-client | ^4.8.1 |
| 国际化 | i18next + react-i18next | ^24.2.2 / ^15.4.0 |
| 构建系统 | Webpack 5 | ^5.97.1 |
| 打包 | electron-builder | ^26.0.12 |
| 单元测试 | Jest + ts-jest + Testing Library | ^30.0.5 / ^29.4.0 |
| E2E 测试 | Playwright | ^1.52.0 |
| 代码检查 | ESLint + typescript-eslint | ^9.20.1 / ^8.24.0 |
| 格式化 | Prettier | 3.4.2 |
1万+

被折叠的 条评论
为什么被折叠?



