
OpenPLC 编辑器是一款跨平台的桌面 IDE基于Electron运行时构建结合了 React 驱动的渲染进程与 Node.js 主进程提供专业的 PLC 编程能力。该技术栈中的每一项技术选择都有其明确目的从 IEC 61131-3 语言编辑器到实时工业协议通信整个技术栈针对工业自动化工具的独特需求进行了深度优化。运行时与语言基础在底层编辑器运行于Electron v35之上为 UI 提供了 Chromium 渲染引擎并为系统级操作提供了 Node.js 运行时。整个代码库使用TypeScript 5.4编写并启用了严格模式编译器输出和 lib 环境均目标设定为 ES2022。这种组合使项目能够访问现代 JavaScript 特性如顶层 await、私有类字段、structuredClone同时在主进程、渲染进程和共享中间件层之间保持类型安全。Node.js 引擎版本要求为≥20.x 24npm 版本要求为≥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.bridgeAPI。┌──────────────────────────────────────────────────────────────┐ │ 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 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘预加载脚本运行在沙盒上下文中在 BrowserWindow 的webPreferences中启用了sandbox: true。这意味着渲染进程对 Node.js API 拥有零直接访问权——所有通信都必须流经显式暴露的window.bridge方法。当添加新的平台能力时你必须定义一个端口接口实现一个适配器并通过预加载桥接进行连接。前端框架与 UI渲染进程是一个React 18应用使用了支持并发渲染的现代createRootAPI。组件架构遵循原子设计(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硬件配置主板选择、引脚映射、ModbusLadderLD 编辑器梯形图节点与连接FBDFBD 编辑器功能块图流状态Library函数库系统/用户功能块和函数Console日志日志输出与过滤Search搜索全项目搜索与替换History撤销/重做编辑历史栈Workspace工作区布局面板尺寸与可见性File文件操作文件系统交互Modal对话框管理模态框开启/关闭状态VersionControl版本跟踪项目版本状态WebRTC实时通信对等连接状态AIAI 功能AI 辅助编程配置Zustand 引入Immer通过enableMapSet()以可变语法实现不可变状态更新并使用subscribeWithSelector中间件实现细粒度响应性。auto-zustand-selectors-hook包通过自动生成的选择器钩子封装了存储防止组件仅需要部分状态时引发不必要的重新渲染。每个切片遵循工厂模式createXxxSlice(...a)其中...a是 Zustand 的set/get/store元组。这使得切片具备良好的可组合性与可测试性。根存储通过将所有切片工厂展开到单个create()调用中创建——没有嵌套的 reducer也没有 action 分发的样板代码。编辑器集成OpenPLC 编辑器支持全部五种 IEC 61131-3 编程语言每种语言类型采用专门的编辑技术语言编辑器技术包描述结构化文本 (ST)Monaco Editormonaco-editormonaco-editor/react支持语法高亮、自动补全的完整代码编辑器指令表 (IL)Monaco Editormonaco-editor支持 PLC 语言的文本编辑器梯形图 (LD)自定义画布编辑器react-draggable 自定义渲染触点/线圈可视化编程功能块图 (FBD)React Flowxyflow/reactv12基于节点的图编辑器顺序功能图 (SFC)React Flowxyflow/reactv12步骤/转换图编辑器Monaco Editor(v0.54) 与驱动 VS Code 的编辑器引擎相同通过monaco-editor/react集成并使用monaco-editor-webpack-plugin进行优化打包配置中包含对 Python 语言的支持以用于 PLC 编译器集成。React Flow(xyflow/reactv12) 为 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 技术栈编辑器还集成了多个为其工业自动化能力提供动力的领域特定库库版本用途avr8js0.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 类型检查 LSPavr8js库尤为引人注目它是一个用纯 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.tselectron-main支持 HMR 的开发环境主进程webpack.config.main.prod.tselectron-main生产环境主进程 预加载打包、Terser 压缩webpack.config.preload.dev.tspreload开发环境预加载脚本编译webpack.config.renderer.dev.tsweb/electron-renderer包含 React Refresh、CSS 模块、Monaco 插件的开发环境渲染进程webpack.config.renderer.prod.tsweb/electron-renderer生产环境渲染进程优化webpack.config.renderer.dev.dll.tsweb用于加速开发环境重构建的 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、WindowsNSIS 安装程序x64和 LinuxAppImagex64的特定平台配置。外部二进制文件编译器工具、平台资源在安装时通过scripts/download-binaries.ts下载并打包至特定平台的extraResources目录中。质量与开发者体验项目通过分层的工具链强制保障代码质量ESLint 9搭配typescript-eslintrecommended-type-checked 配置、react-hooks插件、react-refresh插件以及用于确定性导入排序的simple-import-sortPrettier 3搭配prettier-plugin-tailwindcss实现自动类名排序Huskylint-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.5UI 框架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.67XML 处理fast-xml-parser xmlbuilder2^5.6.0 / ^3.1.1仿真avr8js0.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.0E2E 测试Playwright^1.52.0代码检查ESLint typescript-eslint^9.20.1 / ^8.24.0格式化Prettier3.4.2