首页
/ Penpot 插件 API 1.0 升级指南:Beta changelog 中的破坏性变更、废弃项与新增能力全解析

Penpot 插件 API 1.0 升级指南:Beta changelog 中的破坏性变更、废弃项与新增能力全解析

2026-09-07 13:41:06作者:殷蕙予

本篇文章以 Penpot 仓库中 docs/plugins/beta-changelog.md 为核心骨架,系统拆解 Penpot 插件 API 1.0 版本发布时的全部变更:包括类型命名去前缀、frameboard 等 UI 对齐重命名、事件监听从"传回调退订"改为"按 id 退订"、一批 getXxx 方法被只读属性取代,以及评论、导出、撤销块、标尺参考线、原型能力访问等新增特性。文中逐条结合 插件类型定义插件运行时实现插件 API 测试套件 等仓库源码给出佐证,帮助插件开发者据此编写一份可落地的迁移清单。

一、版本背景:为什么 1.0 是一个里程碑

Beta changelog 的开篇明确了这一版本的定位:1.0 是插件 API 进入稳定阶段的标志。项目承诺自该版本起将尽力不再引入新的破坏性变更,若必须废弃,也会尽量让废弃行为保持向后兼容——旧行为在下一个版本仍可用,但会在后续版本中彻底移除。因此,凡是运行在 1.0 之前 API 之上的存量插件,都值得对照本文进行一次系统性升级,避免在未来版本中失效。

与本文档配套的资源,在仓库中均有对应实体可供核对:

文档中提到的资源 本仓库对应位置
重新编写的 API 文档 docs/plugins/api.md
插件创建与开发教程 docs/plugins/getting-started.mddocs/plugins/create-a-plugin.mddocs/plugins/deployment.md
插件 API 类型定义(1.0 命名规范的最终形态) plugins/libs/plugin-types/index.d.ts
插件运行时(真实提供给插件的 penpot 全局对象实现) plugins/libs/plugins-runtime/src/lib/api/index.ts
API 测试套件与可用样例插件 plugins/apps/plugin-api-test-suiteplugins/apps

二、命名规范重构:去掉 Penpot 前缀

1.0 最宏观的调整是类型命名统一去掉 Penpot 前缀。此前形如 PenpotShapePenpotFilePenpotPage 的类型,现在直接叫 ShapeFilePage

之所以能安全去前缀,是因为 1.0 起插件运行在独立的命名空间中,penpot 前缀(命名空间)与类型本身已经能形成足够清晰的区分,继续把 Penpot 粘在类型名上反而冗余。在当前仓库的 plugins/libs/plugin-types/index.d.ts 中可以确认这一命名结果:例如 ShapeFilePageBoardRectangleEllipseBooleanGuideXBounds 等都是去前缀后的顶层导出类型;文档中强调完整清单以 API 文档为准,本仓库内的 docs/plugins/api.md 即为其本地镜像。

对插件作者的影响集中在 import 语句与 JSDoc/TS 注解 的机械替换上。若使用 TypeScript,重命名后类型往往能直接从 penpot 全局环境自动推断,可进一步减少显式类型标注。

三、与 UI 对齐的类型/方法重命名

为了让 API 术语与 Penpot 界面保持一致,1.0 做了四组语义性重命名。注意:这四组不只是类型改名,还连带改了构造函数与字段名,属于名副其实的破坏性变更。

3.1 frameboard

Penpot 界面中"画板(Board)"概念取代了旧的"帧(Frame)"叫法,全部联动改名如下:

旧名称(1.0 前) 新名称(1.0 起)
PenpotFrame 类型 Board 类型
penpot.createFrame() penpot.createBoard()
shape.frameX / shape.frameY shape.boardX / shape.boardY
PenpotFrameGuideX 类型 GuideX 类型

源码佐证:

3.2 rectrectangle

旧名称 新名称
PenpotRectangle 类型 Rectangle 类型

矩形类型 Rectangleindex.d.ts 中定义,属于基础形状(Shape 联合类型)的一员。

3.3 circleellipse

旧名称 新名称
PenpotCircle 类型 Ellipse 类型
penpot.createCircle() penpot.createEllipse()

源码佐证:运行时实现 createEllipse(): Ellipseapi/index.ts),类型定义在 index.d.ts

3.4 boolboolean

旧名称 新名称
PenpotBool 类型 Boolean 类型

布尔形状接口 Booleanindex.d.ts)配合 BooleanType = 'union' | 'difference' | 'exclude' | 'intersection'(第 442 行)使用。这里把缩写词补全为完整单词,符合"去除模糊缩写"的整体趋势。

迁移建议:这四组改动建议用全局搜索 + 批量替换完成,搜索关键词包括 PenpotFramecreateFrameframeXframeYPenpotRectanglePenpotCirclecreateCirclePenpotBool,替换为上文表格中的新名称。注意 frameX/frameY 这类字段名也可能出现在序列化数据或自定义属性读写逻辑中,替换后应结合类型定义编译检查一遍。

四、事件系统重构:penpot.on / penpot.off 改为 id 句柄

1.0 之前,注册监听与移除监听的代码长这样:

// 1.0 之前:off 需要回传原始回调
penpot.on('pagechange', myListener);   // 注册监听
penpot.off('pagechange', myListener);  // 用同一回调注销

这种写法的问题在于:如果回调被包装、绑定或匿名化,调用方很难再拿到"同一个引用"去注销,容易造成监听泄漏。1.0 改为 on 返回一个事件 id,off 直接消费这个 id

// 1.0 起:off 只需传 on 返回的 id
const id = penpot.on('pagechange', myListener); // 注册监听并拿到句柄
penpot.off(id);                                 // 用 id 注销监听

文档同时给出明确承诺:旧行为已被标记为 deprecated——下一版本中依旧可用,但会在后续版本被移除,插件应尽快迁移。

源码佐证:类型定义中 off(listenerId: symbol): void 的签名(plugins/libs/plugin-types/index.d.ts)说明 id 句柄正是这一机制的数据类型;而注册监听的对象统一使用 penpot.on(...),且事件种类由一个 EventsMap(第 1558 行起)描述,其中可以看到与本文档所述新增事件直接对应的条目:

  • shapechange: Shape(第 1587 行):形状变化事件,文档指出使用前需在 props 中携带目标 shapeId(参见第 103-107 行注释示例);
  • contentsave: void(第 1590-1592 行):文件内容在后端保存完成后触发,回调不接收参数。

五、getXxx 方法移除:统一改为只读属性

1.0 移除了一批"查询类"方法,全部收敛为等价的属性访问,风格从"命令式取数"转向"声明式状态":

被移除的方法 替代写法(属性)
getPage() currentPage
getFile() currentFile
getTheme() theme
getSelected() selection
getSelectedShapes() selection(与原 getSelectedShapes 语义一致)

源码佐证(均可在 plugins/libs/plugin-types/index.d.tsContext 接口中找到):

  • readonly currentFile: File | null(第 810 行),注释示例给出 const fileData = context.currentFile;
  • readonly currentPage: Page | null(第 820 行);
  • readonly theme: Theme(第 898 行),取值集合为 'light' | 'dark'(主题类型定义见第 4458 行附近);
  • selection: Shape[](第 914 行),即当前选中的形状数组。

注意 getSelectedgetSelectedShapes 的语义差异:selection 属性对齐的是后者的语义(返回 Shape[])。另外文档提示 getSelected 原本返回的选中信息在 1.0 中统一由 selection 承担,插件代码中如需"选中的 id 列表",可通过 selection 中每个 Shapeid 字段推导。

迁移范例

// 1.0 之前
const page = penpot.getPage();
const file = penpot.getFile();
const theme = penpot.getTheme();
const shapes = penpot.getSelectedShapes();

// 1.0 起
const page = penpot.currentPage;
const file = penpot.currentFile;
const theme = penpot.theme;
const shapes = penpot.selection;

六、1.0 新增能力逐项拆解

Beta changelog 列出了大量新增 API,下面结合类型定义与运行时实现逐类说明其用途与在源码中的位置。

6.1 注释(Comments)支持

新增对设计评论的读写能力。类型定义中有 Commentindex.d.ts,用于在设计与原型上提供反馈)、CommentThread(第 605 行,"一系列按创建时间排序的评论")等接口,CommentThread 通过 comments 字段(第 634 行附近)以数组形式列出归属于该线程的评论,并支持按所有者删除评论(第 595 行附近)。文档中在介绍评论能力时将其定位为"直接在设计稿上提供反馈",因此常与注释定位(position)相关字段配套使用。

6.2 文件导出(Export files)

File 类型(index.d.ts)新增了导出方法 export(...)(第 1659 行)。与其配套的 Export 接口(第 1596-1605 行)指明可导出文件格式为 png / jpeg / webp / svg / pdf,位图格式还可通过 scale 字段控制导出分辨率。典型场景是把画板批量导出为设计交付物或预览图。

6.3 撤销块(Undo blocks)

插件对画布做批量修改时,如果希望用户一次 Ctrl/Cmd+Z 就能回退整组操作,就需要"撤销块"。对应类型为 HistoryContextindex.d.ts),提供:

  • undoBlockBegin(): Symbol:开启一个撤销块并返回块 id(第 2380 行附近);
  • undoBlockFinish(blockId: Symbol): void:结束该撤销块,块内所有操作将被整体撤销(第 2391 行附近)。

6.4 标尺参考线(Ruler guides)

新增对页面/画板标尺参考线的控制能力,类型定义中有 Guide(联合类型)与 GuideColumn / GuideRow / GuideSquare 及对应的参数类型 GuideColumnParamsGuideSquareParams 等(index.d.ts)。这解释了为何 1.0 会把 PenpotFrameGuideX 改名为 GuideX(见第三节):参考线体系从"仅帧内竖线"扩展成了列/行/方格三种形态的通用能力。

6.5 原型(Prototype)能力访问

插件开始可以访问/操作 Penpot 的原型系统。源码中 Interaction(第 2450 行附近)注释明确说明:"Penpot 允许你通过连接画板(可作为屏幕)来原型化交互",Flow(第 1852 行)描述原型流程,交互动作与触发器通过 Action(第 148 行)/触发器枚举与 addInteraction(第 4072 行附近)等方法暴露,典型如 shape.addInteraction('click', { type: 'navigate-to', destination: anotherBoard })(第 4075 行示例)。

6.6 新增事件:contentsaveshapechange

如第四节所述,EventsMap 中新增了 contentsave(文件保存后触发)与 shapechange(形状变更时触发)。前者可用来做"保存后同步/刷新外部数据",后者需要注意传入 shapeId 以指明监听哪个形状(见 index.d.ts)。

6.7 文件/页面模型增强:file.pagescreatePageopenPage

  • File 类型新增只读属性 pages: Page[]index.d.ts),列出当前文件的所有页面;
  • 运行时实现新增 createPage(): Pageplugins/libs/plugins-runtime/src/lib/api/index.ts)与 openPage(page, newWindow?)(同文件第 351 行),类型签名 openPage(page: Page | string, newWindow?: boolean): Promise<void>index.d.ts)。

官方在类型注释(第 1280 行附近)给出一个重要实操提醒:新建页面后需要先 await penpot.openPage(page) 使其成为活动页,再执行形状变更操作,否则修改会作用到错误的目标页。createPage 同样需要在打开后才向其中添加内容(第 1295 行附近注释)。

6.8 形状模型增强:shape.parentpage.rootshape.visible

  • ShapeBase 新增只读字段 parent: Shape | nullparentIndexindex.d.ts),形状可以沿着父链向上遍历层级树;
  • Context 新增 readonly root: Shape | null(第 799 行),给出当前页面/文档的根形状引用;
  • 形状新增 visible: boolean 属性(第 3736 行),用于读取或控制形状的显示/隐藏状态,这是此前插件必须通过复制属性等间接手段才能完成的操作。

6.9 几何工具:shape.boundsshape.center

形状新增只读 boundsindex.d.ts),返回由 { x, y, width, height } 组成的矩形边界(Bounds 类型定义见第 454 行),即形状在不旋转/变形情况下的包围盒。同时插件工具对象上提供 geometry.center(shapes)center(shapes: Shape[]): { x: number; y: number } | null(第 1389 行),传入形状数组即可计算整体中心点;ContextUtils 下还有等价的 penpot.utils.geometry.center(第 1492 行示例)。配合自动布局与对齐类插件非常实用。

6.10 组件解绑:detach 方法

形状模型新增 detach(): voidindex.d.ts),用于把形状从其所属的组件实例中解绑——解绑后该形状不再受组件主定义同步影响,可以自由编辑。这在"实例局部定制"类插件里是刚需。

6.11 视口控制:penpot.viewport.zoomToShapes

文档记录 1.0 新增 penpot.viewport.zoomToShapes(...),用于把视口缩放到让指定形状可见。从当前仓库 Viewport 接口 看,视口命名空间提供的同类能力包括可写的 center: Pointzoom: number、只读 bounds,以及 zoomReset()zoomToFitAll()(缩放至页面所有形状)、zoomIntoView(shapes)(缩放至参数指定的形状集合)。zoomIntoView(shapes: Shape[]): void(第 5742 行)与 changelog 中"改变视口以查看这些形状"的描述语义一致,可以推断该能力在后续类型定义中进一步演化/细分——建议以仓库中当前的类型签名为准进行编码。

七、迁移速查清单

将 Beta changelog 的变更要点收敛为一份可直接对照执行的清单:

变更类别 旧写法 新写法/新名称
类型命名 PenpotShape/PenpotFile 去掉 Penpot 前缀
画板概念 PenpotFramepenpot.createFrameframeX/frameY Boardpenpot.createBoardboardX/boardY
矩形 PenpotRectangle Rectangle
椭圆 PenpotCirclepenpot.createCircle Ellipsepenpot.createEllipse
布尔 PenpotBool Boolean
参考线 PenpotFrameGuideX GuideX
事件注销 penpot.off('pagechange', listener) const id = penpot.on(...)penpot.off(id)
文件/页/主题/选中态 getFile()/getPage()/getTheme()/getSelected()/getSelectedShapes() currentFile/currentPage/theme/selection(用 selection 统一表示)

建议的升级步骤:

  1. 全局搜索第三节所列的旧方法名与旧类型名,按表格逐一替换;
  2. 将所有 penpot.off(event, callback) 重写为"保存 on 返回值 → 用 id 注销"的形式,防止未来版本移除旧行为后失效;
  3. getXxx() 调用改为属性访问,注意 getSelectedgetSelectedShapes 合并为 selection 的语义变化;
  4. 视项目需求采纳新增能力(撤销块、导出、参考线、几何工具等),新代码优先使用 1.0 命名;
  5. 若项目使用 TypeScript,可直接以 plugins/libs/plugin-types/index.d.ts 为类型源做编译校验;亦可参考仓库内 plugins/apps/plugin-api-test-suite 中各 *.test.ts(如 pages.test.tsshapes-types.test.tsshapes-geometry.test.ts)观察新 API 的真实调用方式,以及 plugins/apps/ 下各示例插件(如 create-palette-plugintable-pluginrename-layers-plugin)在真实场景中的用法。

八、总结:面向未来兼容的升级

Penpot 插件 API 1.0 的 Beta changelog 传达了两个关键信号:

  1. 语义统一:去掉冗余前缀、补全缩写(rectrectangleboolboolean)、对齐产品 UI(frameboard)、把命令式 getXxx 收敛为只读属性,整体让 API 更接近"描述状态"而非"发起查询";
  2. 稳定承诺:1.0 之后项目将尽量不再引入破坏性变更,遗留行为也会以向后兼容的方式废弃。因此现在完成向 1.0 的迁移,等价于为插件的长期可用性上了一道保险。

需要对照最新 API 细节时,可随时查阅仓库内 docs/plugins/api.md(Beta changelog 中所指官方 API 文档的本地版本)与 docs/plugins/faq.md 等配套文档;涉及类型签名、事件表与工厂方法的最新状态,则以 plugins/libs/plugin-types/index.d.tsplugins/libs/plugins-runtime/src/lib/api/index.ts 中的实际声明为准。

登录后查看全文
热门项目推荐
相关项目推荐