lowcode-engine Workspace 应用级 API 完全指南:基于多窗口模型开发低代码设计器
2026/9/14 8:30:11 网站建设 项目流程

lowcode-engine Workspace 应用级 API 完全指南:基于多窗口模型开发低代码设计器

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

本指南以 docs/docs/api/workspace.md 为核心,结合packages/workspacepackages/typespackages/shellpackages/engine的源码实现,系统讲解 lowcode-engine 的 Workspace 模块——一套面向"应用级低代码设计器"的 API 体系。读完本文,你将掌握 Workspace 的变量、方法、事件与配套类型,理解"资源(Resource)→ 资源类型(ResourceType)→ 窗口(Window)→ 视图(EditorView)"的四层模型,并能够在真实项目中基于enableWorkspaceMode搭建多窗口、多资源的低代码设计器。

模块定位:从页面级设计器到应用级设计器

Workspace 模块在 docs/docs/api/workspace.md 中的定位是"通过该模块可以开发应用级低代码设计器"。它对应@since v1.1.0引入的公测能力,文档头部明确标注为@experimental——根据 docs/docs/api/index.md 的约定,experimental表示该模块处于公测阶段,API 可能发生变化,接入时应注意锁定版本并关注更新。

与单文档(页面)级设计器不同,应用级设计器的核心诉求是:一个设计器内同时管理多个"资源"(如页面、表单、区块),每个资源拥有独立的编辑窗口,窗口内部又可以按需切换多种视图(如设计视图、源码视图、WebView)。Workspace 模块正是为此提供的完整运行时与 API 支撑。

在源码层面,该能力由独立的 packages/workspace 包实现,对外通过packages/shellWorkspace壳层暴露为标准的IPublicApiWorkspace,类型定义位于 packages/types/src/shell/api/workspace.ts。入口在 packages/workspace/src/index.ts,核心类Workspace实现在 packages/workspace/src/workspace.ts。

四层核心模型:Resource / ResourceType / Window / EditorView

在展开 API 之前,先厘清 Workspace 依赖的四层对象模型,后续所有方法都是围绕它们运作的:

模型实现位置职责
Workspacepackages/workspace/src/workspace.ts应用级设计器运行时,管理资源注册、窗口队列与全局事件
ResourceTypepackages/workspace/src/resource-type.ts一类资源的"类型定义"(如 Page、Block),决定资源是editor还是webview
Resourcepackages/workspace/src/resource.ts一个具体资源实例(某张页面),持有资源数据、视图集合与导入/保存钩子
EditorWindowpackages/workspace/src/window.ts一个可独立渲染的编辑窗口,窗口内再挂载若干EditorView视图上下文

EditorWindow内部维护一个WINDOW_STATE状态机(packages/workspace/src/window.ts):sleep(睡眠,延迟加载)、active(激活)、inactive(未激活)、destroyed(销毁)。打开窗口时传入sleep参数即可实现"懒初始化",这是多窗口场景下控制性能的关键机制。

视图层由 packages/workspace/src/context/base-context.ts(基础上下文)与 packages/workspace/src/context/view-context.ts(视图上下文)承载:每个视图会构建独立的EditorDesignerSkeletonProjectPluginManager等实例;当视图类型为webview时,则通过 packages/workspace/src/inner-plugins/webview.tsx 注册一个内联iframe插件来渲染外部地址。

变量(Variables)

Workspace 的只读属性均采用 getter 模式导出,符合 docs/docs/api/index.md 中"属性的导出统一用.xxxgetter"的约定。

isActive:是否启用 workspace 模式

get isActive(): boolean;

表示当前引擎是否运行在 workspace 模式。在 packages/engine/src/engine-core.ts 中,当初始化参数enableWorkspaceMode为真时,引擎会调用innerWorkspace.setActive(true)并触发initWindow(),随后isActive返回true

window:当前设计器窗口模型

get window(): IPublicModelWindow;

当前激活的编辑窗口。其 Shell 实现见 packages/shell/src/model/window.ts,内部持有IEditorWindow;若当前没有窗口,IPublicApiWorkspace类型声明中其为IPublicModelWindow | null(见 packages/types/src/shell/api/workspace.ts)。窗口模型IPublicModelWindow的完整属性与方法(idtitleiconresourceimportSchemasavechangeViewType等)记录在 docs/docs/api/model/window.md。

plugins:应用级插件注册

get plugins(): IPublicApiPlugins;

Workspace 层面的插件管理器,用于注册/初始化应用级插件(与单窗口内的视图级插件相区分)。源码中由this.context.innerPlugins提供,见 packages/workspace/src/workspace.ts,API 详见 docs/docs/api/plugins.md。插件注册级别通过IPublicEnumPluginRegisterLevelWorkspace/Resource/EditorView等)区分作用域,相关逻辑在 packages/workspace/src/context/base-context.ts。

skeleton:应用级面板管理

get skeleton(): IPublicApiSkeleton;

Workspace 工作台的面板骨架(顶栏、左栏、主区域、底栏等区域的注册与管理),API 详见 docs/docs/api/skeleton.md。工作台 UI 布局由 packages/workspace/src/layouts/workbench.tsx 渲染,其中TopAreaLeftAreaSubTopAreaMainAreaBottomArea等区域均来自 skeleton。

windows:当前设计器的编辑窗口列表

get window(): IPublicModelWindow[];

(注意:类型声明处源码写法为get windows(): IPublicModelWindow[],文档中笔误为window。)这是全部已打开的编辑窗口数组,Shell 层在 packages/shell/src/api/workspace.ts 中逐个包装为ShellWindow。窗口列表是 MobX 可观察数据(@obx.ref windows,见 packages/workspace/src/workspace.ts),因此新增/删除窗口会驱动 workbench.tsx 自动重渲染。

resourceList:当前设计器的资源列表数据

get resourceList(): IPublicModelResource;

资源树列表(如左侧资源面板展示的页面列表)。Shell 层实现在 packages/shell/src/api/workspace.ts:内部调用getResourceList()并将每个IResource包装为ShellResource。资源模型属性(titleidnametypecategoryiconoptionsconfig等)详见 docs/docs/api/model/resource.md。

方法(Methods)

registerResourceType:注册资源类型

/** 注册资源 */ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void;

注册一种资源类型。实现位于 packages/workspace/src/workspace.ts:将resourceTypeModel包装为ResourceType存入resourceTypeMap;并且——一个关键行为——当 workspace 已激活(_isActive)、尚未创建任何窗口、且存在默认资源类型时,会自动调用initWindow()打开第一个窗口。因此注册资源类型通常应在引擎初始化、workspace 激活之前完成。

IPublicTypeResourceType定义在 packages/types/src/shell/type/resource-type.ts,它本身是一个"可调用对象",签名如下:

interface IPublicTypeResourceType { resourceName: string; // 资源类型唯一名称,如 'Page' resourceType: 'editor' | 'webview' | string; // 资源类型:编辑器型 / WebView 型 (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig; }

调用后返回的IPublicResourceTypeConfig定义在 packages/types/src/shell/type/resource-type-config.ts,包含:

字段说明
description?资源描述
icon?资源图标(React 元素或组件)
defaultViewName默认视图名称
editorViews该资源拥有的视图定义列表(IPublicTypeEditorView[]
init?资源初始化钩子
save?保存钩子,入参为{ [viewName]: any }的 schema 聚合对象
import?导入钩子,返回{ [viewName]: any }
defaultTitle?默认标题
url?resourceType'webview'时,返回要渲染的地址

IPublicTypeEditorView定义在 packages/types/src/shell/type/editor-view.ts,同样是可调用对象:(ctx, options) => IPublicEditorViewConfigIPublicEditorViewConfig(packages/types/src/shell/type/editor-view-config.ts)提供视图级initsaveurl钩子。也就是说,资源的 save/import 会聚合其下所有视图的 save 结果,形成按 viewName 分组的 schema 结构——这一聚合逻辑实现在 packages/workspace/src/window.ts 的EditorWindow.save()importSchema()中。

setResourceList:设置设计器资源列表数据

setResourceList(resourceList: IPublicResourceList) {}

设置资源树列表。实现见 packages/workspace/src/workspace.ts:将每项资源数据IPublicResourceData转换为Resource实例(通过getResourceType(d.resourceName)找到对应资源类型),随后触发resource.list.change事件,供onResourceListChange订阅者消费。

IPublicResourceData定义在 packages/types/src/shell/type/resource-list.ts,IPublicResourceList即其数组类型:

interface IPublicResourceData { resourceName: string; // 资源名(必须对应已注册的 ResourceType) config?: { [key: string]: any }; // 资源扩展配置 title?: string; // 资源标题 id?: string; // 资源 Id category?: string; // 分类 viewName?: string; // 资源视图 icon?: ReactElement; // 资源图标 options: { [key: string]: any }; // 资源其他配置(作为资源初始化第二参数) children?: IPublicResourceData[]; // 资源子元素,支持树形嵌套 }

Resource的构造过程(packages/workspace/src/resource.ts)会按children递归构建子资源,并读取editorViews建立viewName → EditorView映射;其titleicon等字段支持"资源数据优先、资源类型兜底"的取值策略(如resourceData.title || resourceTypeInstance.defaultTitle,见 packages/workspace/src/resource.ts)。

openEditorWindow:打开视图窗口

/** * 打开视图窗口 * @deprecated */ openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>; /** 打开视图窗口 */ openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>;

打开(或激活)一个编辑窗口,存在两套签名:旧签名按(资源类型名, id, 附加参数, 视图名, 是否睡眠)打开;新签名直接传入Resource实例,并可选sleep表示延迟初始化。Shell 层在 packages/shell/src/api/workspace.ts 中通过判断首参是否为字符串来分发到openEditorWindowopenEditorWindowByResource

核心实现逻辑(packages/workspace/src/workspace.ts)值得注意:

  • 若当前窗口仍在初始化中(!window.sleep && !window.initReady),新请求会被推入windowQueue队列,待窗口init()完成后由checkWindowQueue()依次消费(packages/workspace/src/workspace.ts);
  • 若目标资源对应的窗口已存在,则直接切换为激活窗口(必要时先完成其sleep态初始化);
  • 若不存在,则创建新的EditorWindow,追加到windowseditorWindowMap,初始化后依次触发emitChangeWindow()emitChangeActiveWindow()

窗口初始化流程(EditorWindow.init(),packages/workspace/src/window.ts):先初始化全部视图类型 → 执行各视图init→ 等待各视图 simulator renderer ready 后触发onWindowRendererReady→ 解析url→ 设置默认视图 → 标记initReady→ 消费窗口队列 → 激活。

openEditorWindowById:通过视图 id 打开窗口

openEditorWindowById(id: string): void;

按窗口唯一 id 激活已存在的窗口。实现见 packages/workspace/src/workspace.ts:从editorWindowMap取窗口,将旧窗口置为inactive,若目标窗口处于sleep态则先完成初始化,随后触发emitChangeActiveWindow()并将新窗口置为active

removeEditorWindow:移除视图窗口

/** * 移除视图窗口 * @deprecated */ removeEditorWindow(resourceName: string, id: string): void; /** * 移除视图窗口 */ removeEditorWindow(resource: Resource): void;

移除窗口,同样提供旧/新两套签名。核心私有方法remove(index)(packages/workspace/src/workspace.ts)会:从windows中剔除该窗口 → 将旧窗口置为destroyed若被移除的恰是当前激活窗口,则自动将焦点切换到相邻窗口(优先取同下标,其次index + 1index - 1,必要时唤醒其sleep初始化 → 依次触发emitChangeActiveWindow()emitChangeWindow(),最后激活新窗口。可见"移除激活窗口后的焦点转移"是框架自动完成的。

removeEditorWindowById:通过视图 id 移除窗口

removeEditorWindowById(id: string): void;

按窗口 id 移除窗口,等价于removeEditorWindow的 id 版本(packages/workspace/src/workspace.ts)。

事件(Events)

所有事件订阅均遵循 Disposable 模式:返回值为解绑函数,调用即可取消订阅IPublicTypeDisposable定义在 packages/types/src/shell/type/disposable.ts,即() => void

onChangeWindows:窗口新增/删除事件

function onChangeWindows(fn: () => void): IPublicTypeDisposable;

监听窗口列表变化(新增或移除)。触发点在 packages/workspace/src/workspace.ts,窗口打开、移除、initWindow等路径均会调用。典型用途:刷新工作台 Tab 栏、保存窗口快照等。

onChangeActiveWindow:active 窗口变更事件

function onChangeActiveWindow(fn: () => void): IPublicTypeDisposable;

监听当前激活窗口切换。实现在 packages/workspace/src/workspace.ts,同时会级联触发onChangeActiveEditorView(active 视图变更,@since v1.1.7,见 packages/types/src/shell/api/workspace.ts)。

onResourceListChange:资源列表数据变更事件

onResourceListChange(fn: (resourceList: IPublicResourceList): void): (): IPublicTypeDisposable;

监听setResourceList导致的资源列表变化,回调携带最新的资源列表数据。实现基于内部事件总线emittercreateModuleEventBus('workspace')),见 packages/workspace/src/workspace.ts。

补充:IPublicApiWorkspace类型声明中还包含两个文档未展开的事件——onWindowRendererReady(window 下所有视图 renderer 就绪,@since v1.1.7)与onChangeActiveEditorView(active 视图变更,@since v1.1.7),均定义于 packages/types/src/shell/api/workspace.ts,需要时可一并使用。

启用 Workspace 模式:引擎初始化

Workspace 模式由引擎初始化参数控制。在 packages/engine/src/engine-core.ts 中:

if (options && options.enableWorkspaceMode) { // 渲染工作台(WorkSpaceWorkbench) render(createElement(WorkSpaceWorkbench, { workspace: innerWorkspace, ... }), engineContainer); // 是否自动打开第一个窗口(默认为 true) innerWorkspace.enableAutoOpenFirstWindow = engineConfig.get('enableAutoOpenFirstWindow', true); innerWorkspace.setActive(true); innerWorkspace.initWindow(); innerHotkey.activate(false); await innerWorkspace.plugins.init(pluginPreference); return; }

关键点:

  • enableWorkspaceMode: true是进入 workspace 模式的开关;
  • enableAutoOpenFirstWindow(engineConfig,默认true)决定注册首个资源类型后是否自动打开第一个窗口;若设为false,则initWindow()直接返回(packages/workspace/src/workspace.ts),由业务侧通过openEditorWindow手动打开;
  • 首个被注册的资源类型会成为defaultResourceType(packages/workspace/src/workspace.ts),initWindow()会基于它创建第一个EditorWindow

工作台的渲染结构由 packages/workspace/src/layouts/workbench.tsx 定义:TopArea+LeftArea/LeftFloatPane/LeftFixedPane+ 窗口容器(遍历workspace.windows渲染WindowView)+MainArea+BottomArea;当windows为空且配置了workspaceEmptyComponent(engineConfig)时,展示空状态组件。单个窗口的渲染在 packages/workspace/src/view/window-view.tsx:未初始化完成时显示loadingComponent(可配置);resource.type === 'webview'且已解析url时渲染内联iframe(packages/workspace/src/inner-plugins/webview.tsx);否则渲染ResourceView承载各EditorView

典型开发流程:从注册到多窗口管理

综合上述 API 与源码行为,搭建一个应用级设计器的典型流程如下:

  1. 初始化引擎并开启 workspace 模式
import { init, plugins } from '@alilc/lowcode-engine'; await init(document.getElementById('lce-container'), { enableWorkspaceMode: true, // 进入应用级设计器模式 enableAutoOpenFirstWindow: true, // 注册首个资源类型后自动打开第一个窗口 // 其他引擎配置... });
  1. 注册资源类型(在init前后均可,但需保证 workspace 激活前完成注册以触发自动开窗):
import { workspace } from '@alilc/lowcode-engine'; workspace.registerResourceType({ resourceName: 'Page', resourceType: 'editor', (ctx, options) => ({ defaultTitle: '未命名页面', defaultViewName: 'design', editorViews: [ { viewName: 'design', viewType: 'editor', (viewCtx) => ({ /* 视图初始化 / 保存钩子 */ }), }, { viewName: 'preview', viewType: 'webview', (viewCtx) => ({ url: async () => '/preview.html' }), }, ], async save(schema) { /* 按 viewName 聚合保存 schema */ }, async import(schema) { /* 返回 { viewName: schema } 结构 */ }, }), });
  1. 设置资源列表并监听变更
workspace.setResourceList([ { resourceName: 'Page', id: 'p1', title: '首页', options: {} }, { resourceName: 'Page', id: 'p2', title: '关于页', options: {} }, ]); const off = workspace.onResourceListChange((list) => { console.log('资源列表已更新', list); });
  1. 打开 / 切换 / 移除窗口,并监听窗口事件
// 打开资源窗口(sleep 开启延迟初始化) await workspace.openEditorWindow({ resourceName: 'Page', id: 'p1', title: '首页', options: {} }, true); workspace.openEditorWindowById('window-xxxx'); // 按 id 激活 workspace.removeEditorWindowById('window-xxxx'); // 按 id 移除 const offWindows = workspace.onChangeWindows(() => { /* 刷新窗口列表 UI */ }); const offActive = workspace.onChangeActiveWindow(() => { /* 高亮激活窗口 */ });
  1. 通过 window 模型操作当前窗口workspace.window.importSchema(schema)触发资源import钩子并分发到各视图;workspace.window.save()聚合各视图save结果后调用资源save钩子(详见 docs/docs/api/model/window.md)。

小结

Workspace 是 lowcode-engine 面向应用级低代码设计器场景提供的一套完整方案:registerResourceType负责声明资源能力,setResourceList注入资源数据,openEditorWindow/removeEditorWindow系列方法管理多窗口生命周期,三个事件(外加@since v1.1.7的两个补充事件)驱动 UI 与业务联动。其底层通过ResourceType → Resource → EditorWindow → EditorView的分层模型,把"资源类型定义、资源实例、窗口生命周期、视图上下文"彻底解耦,配合sleep懒初始化与windowQueue队列,在保证多窗口可扩展性的同时控制了初始化成本。该模块当前标注为experimental,接入生产环境时建议锁定引擎版本,并关注 docs/docs/api/workspace.md 与 packages/types/src/shell/api/workspace.ts 中 API 的后续演进。

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询