@virid/core
v0.0.1
Published
A lightweight and powerful message core built using dependency injection and ECS concepts
Readme
🛰️ @virid/core
A Lightweight, Message-Driven Logic Engine inspired by Rust's ECS Architecture and Nestjs. 受 Rust Bevy ECS 架构与Nestjs启发的轻量级消息驱动逻辑引擎。
✨ 特点
🧩 什么是 CCS 架构?
virid 采用 CCS (Controller-Component-System) 架构。它在传统 ECS 的基础上,为 Web/UI 环境引入了“控制器”层,实现了逻辑与视图的完美桥接。
1. 💾 Component (数据) —— “逻辑的容器”
- 定义:纯粹的数据结构,不包含任何业务逻辑。
- 职责:存储状态。在
virid中,它是 IoC 容器管理的单例。
2. 🎮 Controller (控制器) —— “视图的锚点”
- 定义:UI 框架(Vue)与核心逻辑(Core)之间的代理。
- 职责:
- 投影 (Projection):将 Component 里的数据安全地映射给 Vue。
- 指令 (Command):接收用户的点击事件,并将其转化为
Message发送给引擎。
3. ⚙️ System (系统) —— “因果的裁判”
- 定义:无状态的静态方法集合,是逻辑变更的唯一合法场所。
- 职责:监听
Message,根据指令修改Component中的数据。它是确定性的,确保同样的输入永远得到同样的输出。
🛠️ 逻辑主权
1. 彻底的 UI 降级:框架无关核心
- 主权移交:UI 框架被剥夺了状态管理与业务调度的权限,退化为纯粹的 “状态投影层”。所有的业务因果律、状态机转换均在
virid Core中闭环执行。 - 物理隔离:Core 层不依赖任何
DOM/BOMAPI。核心逻辑可以无缝运行在 Node.js 服务端、Web Worker、甚至是命令行 (CLI) 工具中。 - 无缝迁移:逻辑资产不再与特定 UI 框架绑定。只需更换一个适配层,就能适配 vue 或React 应用。
2. 生产级的可测试性
- 告别模拟 (Mock) 地狱:无需 JSDOM,无需模拟复杂的浏览器环境。由于核心逻辑是纯 JS/TS 驱动的,可以直接在 Node.js 中启动 Core,通过 “发送消息 -> 断言状态” 的方式,完成对复杂业务流的单元测试。
- 逻辑回放:所有副作用都通过消息触发,让业务逻辑变成纯净的流水线,支持对线上逻辑路径进行离线重构与自动化回归。
3. 强力控制反转
- 深度 IoC 架构:基于 InversifyJS 实现依赖注入。
System、Component与Controller之间通过容器自动装配。 - 动态生命周期:支持逻辑模块的按需加载与自动注入。无论是全局单例的
System还是随组件销毁的Controller,均由容器统一接管生命周期。
🏎️ 游戏级调度引擎
- 确定性 Tick 机制: 引入类 Bevy 的消息循环,所有逻辑变更在 Tick 中推进。
- 双缓冲消息池: 物理隔离“正在处理”与“新产生”的消息,避死循环与逻辑抖动。
- 物理隔离消息策略:
- SingleMessage (信号): 自动合并同类项,同 Tick 内仅触发一次批量处理。
- EventMessage (事件): 严格保序执行,确保逻辑链条的原子性。
🛡️ 状态安全与权限控制
- 只读数据护盾: Controller 层(@virid/vue中)默认获得只读代理,禁止在 System 之外非法篡改 Component 状态。
- 原子修改协议: 强制通过特定的
AtomicModifyMessage变更数据,让每一次状态改变都有迹可循、可被审计。
🧬 声明式元编程
- 装饰器驱动: 使用
@System,@Message,@Inherit,@Project等装饰器,以声明式的方式描述复杂的依赖网络和逻辑响应流。 - 自动数据路由: 消息发送即触发,参数自动注入,无需手动编写复杂的监听与分发代码。
📖 快速上手
只需三步,即可在纯 JS 环境中构建一个受严格保护的状态机。
1. 定义组件与消息 (Component & Message)
组件(Component)是纯粹的数据结构,消息是唯一的驱动契约。
import {
createvirid,
Component,
System,
Message,
SingleMessage,
AtomicModifyMessage,
} from "@virid/core";
// Initialize the core engine
const app = createvirid();
// Define Data Entity (Component)
@Component()
class CounterComponent {
public count = 0;
}
// Register component
app.bindComponent(CounterComponent);
// Define operation instructions (Message)
class IncrementMessage extends SingleMessage {
constructor(public amount: number) {
super();
}
}2. 编写系统 (System)
系统是无状态的静态方法,通过依赖注入获取组件并处理业务逻辑。你无需任何操作,他们是纯static的,virid会自动找到他们并正确地调用他们。
//Define System
class CounterSystem {
@System()
static onIncrement(
@Message(IncrementMessage) message: IncrementMessage,
count: CounterComponent,
) {
console.log("---------------------System----------------------");
console.log("message :>> ", message);
count.count += message.amount;
}
}3. 纯环境运行 (Headless Execution)
无需浏览器,直接在 Node.js 或测试框架中驱动你的业务。
// Business logic automatically completes scheduling in the next microtask
queueMicrotask(() => {
IncrementMessage.send(1);
IncrementMessage.send(5);
queueMicrotask(() => {
AtomicModifyMessage.send(
CounterComponent,
(comp) => {
console.log("----------------AtomicModifyMessage------------------");
console.log("CounterComponent :>> ", comp);
},
"Check CounterComponent",
);
});
});🛠️ 高级工程实践 (Advanced Engineering)
⚓ 全生命周期拦截 (Lifecycle Hooks & Middleware)
virid 提供了深度介入消息管道的能力,你可以轻易地将其扩展为支持 Undo/Redo、状态同步 或 自动日志 的系统。
Middleware: 在消息进入 EventHub 之前进行预处理。
TypeScript
app.useMiddleware((message, next) => { console.log(`Identified message ${message.constructor.name}`); next(); // 继续流转 });AOP Hooks: 针对特定消息的执行前后进行切面处理。
onBeforeExecute: 在 System 逻辑运行前触发(如权限检查)。onAfterExecute: 在逻辑运行后触发(如数据持久化)。
app.onBeforeExecute(IncrementMessage, (message, context) => { console.log("----------------onBeforeExecute------------------"); console.log("message :>> ", message); console.log("targetClass :>> ", context.targetClass); console.log("methodName :>> ", context.methodName); console.log("params :>> ", context.params); });
⚡ 原子修改:“快照”特权 (Atomic Modification)
为了兼顾“严苛约束”与“开发效率”,virid 允许通过 AtomicModifyMessage 直接描述状态变更,而无需编写完整的 System。
- 语义化变更:每一条原子修改都强制要求一个
label,让原本“随意的”赋值操作变得可被审计。 - 一致性保证:原子修改依然遵循 Tick 调度,确保数据变更与 System 逻辑同步生效。
🚨 万物皆消息:健壮的异常监控 (Error as Message)
virid 将异常视为系统的一等公民:
- 自动封装:任何 System 或 Hook 中的同步/异步异常,都会被 Dispatcher 自动捕获并封装为
ErrorMessage。 - 防御式编程:你可以定义一个
ErrorSystem统一处理这些消息(如发送 Sentry 日志或触发 UI 告警),确保核心逻辑引擎永远不会因为单一组件的崩溃而宕机。
🚀 结语:为什么是 virid?
virid 不是在重复造一个状态库,它是在为 Web 开发引入一套具备强确定性的工业标准。
当你的项目从几十个组件增长到几千个,当你的业务逻辑从简单的 CRUD 变成复杂的跨组件联动时,virid 的架构将确保你的代码依然:逻辑可寻迹、修改可预期、测试可脱离 UI。
数据流转示意图
User -->|Dispatch| Writer[MessageWriter]
Writer -->|Middleware| Hub[EventHub: Staging]
Hub -->|Tick/Flip| Active[EventHub: Active]
Active -->|Execute| System[System/Hook]
System -->|Update| Component[Raw Component Data]
Component -->|Reactive| UI[Vue/React View]