docs / 插件 / plugins

插件

NuxtCMS 的插件分两类,都在「后台 → 插件」统一管理:

运行时插件代码包插件
形态一个 JSON 清单 nuxtcms.plugin.json一个 Nuxt Layer(npm 包 / Git 仓库)
能力设置项、注入代码、CSP 白名单、事件 Webhook、定时任务以上全部 + 页面、组件、API、数据库表
安装后台在线安装,无需重新构建,所有部署形态通用plugin.mjs add 后重新构建部署
典型统计代码、在线客服、群机器人通知、搜索推送会员、商城、表单设计器

官方插件中心

官网(https://insightme.top,NUXT_PLUGIN_HUB_URL 可改)就是插件中心,提供一条龙服务:

  1. 注册账号:官网 /account/register。
  2. 绑定站点:官网「账号 → API 令牌」创建令牌,粘贴到站点「后台 → 插件 → 账号与授权」。令牌只保存在服务端。
  3. 在线下载安装:插件市场里点「安装」,免费插件直接装好;有新版本时显示「更新到 vX」。
  4. 积分购买:付费插件标价为积分,点「N 积分购买」即扣积分并为当前域名签发授权。积分暂不支持在线支付,联系管理员充值。
  5. 联系授权:需要多站点授权、试用或报价,点「联系授权」,留言连同域名提交到官网后台,由管理员处理并发放授权码。
  6. 授权关联:授权绑定域名(NUXT_PUBLIC_SITE_URL 的 host)。也可以在插件设置里手动填写授权码。授权每天由 cron 复核一次;插件中心暂时连不上时保留上次结果,不会让正常运行的站点突然失效。

未授权的付费插件可以先安装和配置,但不会生效(不注入代码、不触发 Webhook)。

插件中心不可达时(内网、离线),市场自动切换为框架内置的官方插件(plugins/official/*.json),免费插件照常安装。

运行时插件清单

{
  "id": "my-plugin",
  "name": { "zh": "我的插件", "us": "My plugin" },
  "version": "1.0.0",
  "description": { "zh": "做什么用的", "us": "What it does" },
  "requires": ">=1.3.0",
  "category": "analytics",
  "icon": "i-lucide-bar-chart-3",
  "license": "free",
  "settings": [
    { "key": "siteId", "label": "站点 ID", "type": "text", "required": true }
  ],
  "inject": [
    { "position": "head", "when": "siteId", "html": "<script src=\"https://cdn.example.com/a.js?id={{settings.siteId}}\" async></script>" }
  ],
  "csp": { "script-src": ["https://cdn.example.com"] },
  "webhooks": [
    { "event": "contact.created", "url": "https://hooks.example.com/x", "body": { "text": "{{event.name}}:{{event.message}}" } }
  ],
  "tasks": [
    { "name": "每日同步", "cron": "0 3 * * *", "url": "{{site.url}}/api/cron/xxx", "headers": { "Authorization": "Bearer {{cronSecret}}" } }
  ]
}
字段说明
id小写字母、数字、短横线,全局唯一
name / description / label / help字符串或 { "zh": "...", "us": "..." }
versionsemver;市场据此提示更新
requires需要的最低 NuxtCMS 版本
license / priceCreditsfree 或 paid(付费插件只能从插件中心安装)
settings[].typetext textarea number boolean select secret url;secret 不回显给浏览器
inject[]position: head / body;scope: public(默认,只在前台)/ all;when: 某个设置为真时才注入;raw: true 表示设置值本身就是 HTML(不转义)
csp注入代码需要的外部域名。只有真正注入了代码的页面才会放开,没装插件的站点保持严格策略
webhooks[]event 见下表;url / headers / body 都可以用模板
tasks[]安装时写入「定时任务」,由 cron 调度器执行;插件停用时任务一起停用,卸载时删除

模板变量

{{settings.xxx}}、{{site.url}}、{{site.name}}、{{event.xxx}}(Webhook)、{{cronSecret}}(任务)。注入 HTML 时变量会做 HTML 转义,防止设置值破坏页面。

事件

事件时机载荷
contact.created前台提交联系表单name email phone message createdAt
content.published文章 / 页面 / 产品发布(含定时发布到点)kind id title slug locale status url
content.updated内容被修改同上
content.deleted内容被删除同上
plugin.installed插件安装或更新id version updated

Webhook 在响应之后执行(Cloudflare 上用 waitUntil),失败只记日志,不影响用户操作。

本地调试

「后台 → 插件 → 开发者」可粘贴或上传清单直接安装,修改后再次导入即覆盖(设置保留)。

代码包插件

一个普通的 Nuxt Layer,根目录放 nuxtcms.plugin.json("kind": "package"),在 Nitro 插件里注册:

// server/plugins/my-plugin.ts
import manifest from '../../nuxtcms.plugin.json'

export default defineNitroPlugin(() => {
  defineCmsPlugin(manifest, ({ on }) => {
    on('content.published', async (payload) => {
      // 插件停用或未授权时不会被调用
    })
  })
})

代码包插件给后台加菜单(app.config.ts):

export default defineAppConfig({
  nuxtcms: { adminNav: [{ label: '我的插件', icon: 'i-lucide-puzzle', to: '/admin/my-plugin', adminOnly: true, after: 'plugins' }] },
})

在 API 里判断是否可用、读取设置:

export default defineEventHandler(async (event) => {
  if (!(await isPluginActive(event, 'my-plugin'))) throw createError({ statusCode: 404 })
  const settings = await getPluginSettings(event, 'my-plugin')
  // ...
})

安装 / 卸载(在站点项目目录执行,然后重新构建部署):

node node_modules/nuxtcms/scripts/plugin.mjs list
node node_modules/nuxtcms/scripts/plugin.mjs add my-plugin --license NCMS-XXXX   # 从插件中心按 id 安装
node node_modules/nuxtcms/scripts/plugin.mjs add github:you/nuxtcms-plugin-x#v1.0.0
node node_modules/nuxtcms/scripts/plugin.mjs remove my-plugin

CLI 会用项目的包管理器安装依赖,并记录到 nuxtcms.plugins.json;基座的 nuxt.config.ts 自动 extends 其中的包。带 --license 时授权码随构建下发,首次访问后台或 cron 运行时自动绑定并校验。

发布到官方插件中心

把清单(运行时插件)或包地址(代码包插件)提交给管理员,在官网后台「插件中心 → 插件」上架、定价(积分)。站点下次打开插件市场即可看到。