news 2026/7/11 2:11:00

OpenPLC Editor v4之技术栈

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenPLC Editor v4之技术栈

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 <24,npm 版本要求为≥10.x,以确保项目运行在当前的 LTS 版本线上。TypeScript 配置了esModuleInteropallowSyntheticDefaultImports,旨在与 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 3class-variance-authority (CVA)对其进行样式定制。这种组合在保留无障碍访问性的同时,赋予了完全的设计控制权。项目使用的 Radix 基元包括 Accordion、Dialog、Dropdown Menu、Popover、Select、Tabs、Toast、Tooltip 等。Lucide ReactRadix Icons提供了图标集。

Tailwind 配置了自定义设计令牌系统:brand调色板使用 CSS 自定义属性(从--primary-light--primary-dark)来实现运行时主题切换,自定义字体系列(用于展示的Poppins,用于说明文本的Inter)保持了工业 IDE 的视觉美学。暗模式采用基于类名的策略(darkMode: 'class')。

状态管理

应用状态由Zustand 5结合切片组合模式进行管理。根状态并非采用单一庞大的存储,而是由 16 个独立的切片组装而成,每个切片定义了各自的状态形状和操作:

切片领域核心职责
Project项目生命周期创建、打开、保存、POU 管理
Editor编辑状态活动编辑器、选择、光标
Tabs选项卡导航打开/关闭/聚焦选项卡管理
Device硬件配置主板选择、引脚映射、Modbus
LadderLD 编辑器梯形图节点与连接
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-editor+@monaco-editor/react支持语法高亮、自动补全的完整代码编辑器
指令表 (IL)Monaco Editormonaco-editor支持 PLC 语言的文本编辑器
梯形图 (LD)自定义画布编辑器react-draggable+ 自定义渲染触点/线圈可视化编程
功能块图 (FBD)React Flow@xyflow/reactv12基于节点的图编辑器
顺序功能图 (SFC)React Flow@xyflow/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 类型检查 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()以原生支持存储状态中的MapSet

构建与打包流水线

构建系统是自定义的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)、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
仿真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.0
E2E 测试Playwright^1.52.0
代码检查ESLint + typescript-eslint^9.20.1 / ^8.24.0
格式化Prettier3.4.2
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/11 2:06:19

TS2007FC与PIC18F86J50在嵌入式音频开发中的应用

1. TS2007FC与PIC18F86J50的黄金组合解析在嵌入式音频开发领域&#xff0c;TS2007FC音频放大器与PIC18F86J50微控制器的组合堪称经典搭档。这套方案特别适合需要高保真音频输出与智能控制的场景&#xff0c;比如车载音响系统、智能家居中控、便携式音乐设备等。TS2007FC是一款2…

作者头像 李华
网站建设 2026/7/11 2:06:26

挖矿木马检测实战:基于ATTCK矩阵的5阶段威胁狩猎与自动化响应

基于ATT&CK框架的挖矿木马狩猎实战&#xff1a;从攻击链透视到自动化响应当安全团队发现服务器CPU使用率异常飙升时&#xff0c;往往已经错过了防御的最佳时机。现代挖矿攻击已形成完整的产业化链条&#xff0c;从初始入侵、持久化驻留到横向移动&#xff0c;攻击者采用与企…

作者头像 李华
网站建设 2026/7/11 2:04:33

LangGraph实战:构建可靠AI工作流与多智能体系统开发指南

如果你正在关注AI领域的最新动态&#xff0c;可能已经注意到一个名字频繁出现&#xff1a;Jason Liu。但这个名字背后真正值得关注的&#xff0c;不是又一个技术大牛的传奇故事&#xff0c;而是他代表的一种全新AI开发范式——这种范式正在悄然改变我们构建和部署智能应用的方式…

作者头像 李华
网站建设 2026/7/11 2:03:34

AI绘画面部特写提示词全攻略:从细节控制到风格实战

最近在AI绘画圈子里&#xff0c;有个现象很有意思&#xff1a;很多人在生成人物面部特写时&#xff0c;要么得到模糊的五官&#xff0c;要么面部比例失调&#xff0c;甚至出现"恐怖谷效应"。其实问题往往不在模型本身&#xff0c;而在于提示词&#xff08;Prompt&…

作者头像 李华