凌晨三点,我写下了第一个ReactPress插件
那天晚上,客户突然甩过来一个需求:“文章发布后,自动同步到我们的企业微信群里。”
如果是WordPress,我闭着眼都能写个publish_post钩子。但这次用的是 ReactPress(官网 | GitHub)——一个基于NestJS和React的现代CMS。翻遍文档,我终于在某个角落找到了救星:官方提供的 reactpress-plugin-starter 模板。
于是,一场从零到一的插件开发冒险,就这么开始了。
第一关:克隆那个“潘多拉魔盒”
我打开终端,敲下这行命令,就像打开了新世界的大门:
git clone https://github.com/fecommunity/reactpress-plugin-starter.git my-sync-plugin
cd my-sync-plugin
npm install
目录解压后,我被它的结构惊到了——src/server/和src/admin/分得清清楚楚。好家伙,果然是“前后端分离”的拥护者。
但很快我就被浇了一盆冷水:这玩意儿不像WordPress那样直接扔进wp-content/plugins就行。它需要身份认证。
第二关:给它一个“合法身份”
打开plugin.json,我看到了一个清单:
{
"id": "my-sync-plugin", // 必须是 kebab-case,且和文件夹名一致
"name": "企业微信同步插件",
"version": "1.0.0"
}
再打开package.json,把名字改成@my-scope/reactpress-plugin-wecom-sync。这时候我才明白,ReactPress的插件就像一个个微服务,插件ID就是它在系统中的身份证号——改错了,后台根本认不出来。
关于插件清单的完整规范,可以看官方 插件系统参考文档。
第三关:真正的“魔法”藏在钩子里
最激动人心的时刻来了。我打开src/server/index.ts,看到了那个神秘的register函数:
import type { HookService, PluginContext } from '@fecommunity/reactpress-toolkit/plugin/server';
// ↑ 工具包地址:https://www.npmjs.com/package/@fecommunity/reactpress-toolkit
export function register(hooks: HookService, ctx: PluginContext): void {
// 这就是那个“暗号”!
hooks.addAction('article.afterPublish', async (payload) => {
// payload 里藏着 { article, isNew }
await sendToWeCom(payload.article.title, payload.article.url);
}, { priority: 10, pluginId: ctx.id });
}
看到article.afterPublish的那一刻,我差点从椅子上跳起来——这不就是WordPress的publish_post吗?那种熟悉的感觉瞬间回来了。
但接下来的deactivate函数又提醒我:这不只是简单的钩子,它是热插拔的。启用、禁用、重载,都不需要重启整个API服务。这种体验,对开发调试来说简直是降维打击。
第四关:后台UI的“插槽游戏”
光有逻辑还不够,客户还想要一个设置面板,能开关“是否同步”和“Webhook地址”。
我在plugin.json里找到了admin.menu,又在src/admin/index.ts里看到了registerAdmin:
export function registerAdmin(registry, ctx) {
// 把面板注册到后台菜单里
registry.registerMenu('我的插件设置', <StarterPanel />);
}
更有趣的是,ReactPress还提供了**插槽(Slots)**机制。我甚至可以把设置面板挂在文章编辑器的侧边栏里(article.editor.sidebar.afterPublish),就像给WordPress的编辑器挂载Meta Box一样。
想了解所有内置插槽?参考 主题与插件开发文档。
那种感觉就像在玩乐高——所有的UI块都是积木,插件只是往里塞了一块属于自己的零件。
第五关:配置的“暗箱操作”
配置存在哪儿?藏在globalSetting.plugins.entries.{id}.config里。
我可以通过后台的设置页面修改,也可以用命令行直接PUT:
curl -X PUT http://localhost:3002/api/extension/plugins/my-sync-plugin/config \
-H "Authorization: Bearer <token>" \
-d '{"config":{"enabled":true,"webhook":"https://qyapi.weixin.qq.com/..."}}'
关键的是——改完配置,插件自动重载。我不用再像以前一样,改个配置就得重启整个服务,等得花儿都谢了。
第六关(最折磨的一步):把它塞进ReactPress项目里
写完了代码,npm run build编译出dist/目录。下一步,我得把它放进ReactPress的主项目里:
cp -r my-sync-plugin /path/to/reactpress/plugins/
然后去plugins/package.json里注册一下:
{
"reactpress": {
"local": ["my-sync-plugin"]
}
}
跑起pnpm dev的那一瞬间,我屏住了呼吸。看到终端里跳出“Plugin my-sync-plugin compiled successfully”时,我才长舒一口气。
登录后台 → 插件管理 → 启用。那一刻,我的小插件终于“活”了过来。
通关感悟:这不只是代码,是一种“超能力”
凌晨四点,我对着电脑屏幕发了会儿呆。回首这短短几个小时的冒险,我发现ReactPress的插件系统其实藏着三个设计哲学:
- 边界清晰:服务器逻辑(
src/server)和后台界面(src/admin)被物理分离,各司其职,互不干扰。 - 热加载快感:启用/禁用无需重启API,这在开发时大大缩短了反馈回路。
- 插槽即自由:不只是简单的菜单,你还能把UI“钉”在任何内置编辑器挂载点上,就像给CMS打上定制的补丁。
如果你也想体验这种“掌控感”,别犹豫,去把 reactpress-plugin-starter 拽下来试试。
毕竟,一个好的CMS不只是用来写文章的——它是让你随心所欲重塑内容流程的舞台。而写插件,就是让你成为这场演出的导演。
准备好了吗?你的第一个钩子,正在等你注册。 🎬
📌 快速传送门(文中提到的所有地址)
- ReactPress 官网:https://docs.gaoredu.com/
- ReactPress 源码:https://github.com/fecommunity/reactpress
- 插件 Starter 模板:https://github.com/fecommunity/reactpress-plugin-starter
- 插件系统详细参考:https://github.com/fecommunity/reactpress/blob/master/plugins/README.md
- 工具包 npm:https://www.npmjs.com/package/@fecommunity/reactpress-toolkit
- 主题 Starter(延伸):https://github.com/fecommunity/reactpress-theme-starter
(附:如果中途被依赖问题卡住,记得在package.json里加.npmrc开启legacy-peer-deps——这是我踩过的第一个坑,希望你别再踩了。)
现在所有关键地址都有了,读者不用再自己搜。如果还需要补充其他链接(比如某个特定API端点的文档),随时告诉我,我再塞进去。😊
更多推荐

所有评论(0)