Skip to content

Plugin Prepare

worable edited this page Oct 12, 2026 · 2 revisions

插件开发准备

在 packages/plugins/ 下新建插件包需要三步:从模板生成目录、把它接入 workspace、配置构建脚本。下面的流程同时覆盖内置插件的本地调试与 ZIP 上传包的准备。

使用生成器创建插件

仓库内置了插件脚手架模板 packages/plugins/template,并提供了生成器脚本:

pnpm plugin:create <your-id> --name "显示名称" --frontend

生成器按 packages/plugins/template 的形态生成 packages/plugins/<your-id>(后端入口 src/index.ts,--frontend 时另含前端包)、写入包名与插件 ID、刷新 workspace lockfile 并打印后续步骤。

手工创建等价于:

  1. 复制模板目录:

    cp -r packages/plugins/template packages/plugins/my-plugin
    cd packages/plugins/my-plugin
  2. 修改 package.json 中的包名为 @stackpanel/plugin-my-plugin。

  3. 修改 src/index.ts 中的插件 ID。

  4. 编辑 pnpm-workspace.yaml(如果 packages/plugins/* 已包含则无需修改),然后更新 lockfile:

    pnpm install --no-frozen-lockfile

开发依赖

插件的 package.json 至少需要:

{
  "name": "@stackpanel/plugin-my-plugin",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "node ../../../scripts/build-plugin.mjs",
    "typecheck": "tsc -p tsconfig.json"
  },
  "dependencies": {
    "@stackpanel/sdk": "workspace:*"
  },
  "devDependencies": {
    "@types/node": "^22.20.1",
    "typescript": "^6.0.3"
  }
}

scripts/build-plugin.mjs 是内置插件的标准构建:先 tsc --emitDeclarationOnly 出 .d.ts,再用 esbuild 把源码打包成单文件 dist/index.js(不留裸相对导入,Node ESM 可直接跑)。不要用纯 tsc 直接产出运行入口——共享配置下 moduleResolution: bundler 会留下无扩展名的相对导入,Node ESM 解析不了。也不再用 tsup(已从插件脚手架移除)。

构建配置

内置插件不需要 tsup.config.ts,只用两个 tsconfig:

// tsconfig.json —— 类型检查(noEmit)
{ "extends": "../../../tsconfig.base.json", "compilerOptions": { "noEmit": true, "types": ["node"] }, "include": ["src/**/*.ts"] }

// tsconfig.build.json —— 出声明
{ "extends": "../../../tsconfig.base.json", "compilerOptions": { "noEmit": false, "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "dist", "rootDir": "src", "types": ["node"] }, "include": ["src/**/*.ts"] }

开发流程

  1. 编写插件代码(src/index.ts)。

  2. 编译到 dist/:

    pnpm --filter @stackpanel/plugin-my-plugin build
  3. 若含前端包,编译 frontend/ 并更新前端注册表:

    pnpm build:frontend
  4. 重启 API(开发模式下 tsx watch 会自动重启)。

  5. API 启动时自动 seed 内置插件;非内置插件需打包上传安装。

touch apps/api/src/app.ts 可手动触发 tsx watch 重新 seed 内置插件。

内置插件开发

如果你的插件在 packages/plugins/ 下且被 apps/api 的 package.json 依赖,它会被视为内置插件,API 启动时自动 seed。修改源码后重新构建并重启 API 即可生效。

非内置插件开发

如果你在开发一个将通过 ZIP 上传安装的插件:

  1. 编写并构建。
  2. 打包为 ZIP(见 打包与签名)。
  3. 通过管理后台 /admin/plugins 上传。
  4. 启用插件。

数据模型

插件数据自治:插件不直接持有数据库句柄,不得把业务表写进内核 schema,也不通过数据库句柄操作数据。用 defineModel 声明模型,放进 PluginDefinition.customModels,由内核在激活时建表并暴露类型化访问:

import { defineModel } from '@stackpanel/sdk';
import { z } from 'zod';

export const itemModel = defineModel({
  kind: 'my-plugin/item', // 命名空间/名称
  label: '条目',
  schema: z.object({ title: z.string(), stock: z.number().int().default(0) }),
  indexes: [{ fields: ['stock'], types: { stock: 'integer' } }],
});

读写只经 ctx.extensions(get / list / listAll / create / update / delete / patch)或 ctx.tx 事务。内核同时提供 /custom/<namespace>/<name> 通用 REST 面。PluginContext 不提供任何数据库句柄(ctx.db 已移除),插件拿不到 PrismaClient,也无法绕过 Extension 引擎直连数据库。内核自身的表结构变更与插件无关,属内核维护范畴。

Clone this wiki locally