SuperAPI AI 工具集

bx-sites-plugins

编程与开发

查看项目

更新于 10-16 07:44

技能介绍

BxSites 插件参考

BxSites 插件本身就是一个 BoxLang 模块——它有自己的 box.json 和 ModuleConfig.bx,作为 bx-sites 的同级模块安装在同一运行时中。没有需要导入的插件 API,也没有独立的注册表——BoxLang 自身的模块系统就是插件系统。安装一个模块本身并不会把它激活为插件,需要显式配置:

plugins: [ myBxSitesPlugin ]

(参见 bx-sites-configuration 中的 plugins 键。)

安装已发布的插件

bxSites install:plugin --name=bx-sites-plugin-analytics [--version=1.2.0]

该命令从 ForgeBox 下载并解压到项目根目录的 boxlang_modules/bx-sites-plugin-analytics/(BoxLang 的自动加载本地模块约定——不需要 box/CommandBox,也不需要 BOXLANG_HOME 全局安装步骤)。它会立即将其加载到运行时,并打印真实注册的模块映射名称(不一定与 ForgeBox 上的 slug 相同)——把该名称加入 plugins。可在 ForgeBox 的 bxsites-plugins 分类下浏览已发布的插件。

编写插件

除常规模块脚手架外,只需一个类:models/BxSitesPlugin.bx。每个方法都是可选的——bx-sites 在调用每个钩子前都会检查它是否存在。

bxSites plugin:new --name=my-analytics-plugin [--dest=]

该命令会生成 box.json、ModuleConfig.bx 以及完全打桩的 models/BxSitesPlugin.bx,参照 bx-sites 仓库中的 examples/hello-plugin/(一个完整可运行的参考实现——通过 onPageHtml/onBuildComplete 给每个页面添加 HTML 注释并追加构建摘要)。

class {

struct function onConfig( required struct config ) {
	// 在 bxsites.yaml 加载完成后立即修改/返回站点配置。
	return arguments.config
}

string function onPageMarkdown( required string markdown, required struct page, required struct config ) {
	// 在转换前修改某个页面的原始 markdown。
	return arguments.markdown
}

string function onPageHtml( required string html, required struct page, required struct config ) {
	// 在转换后修改某个页面渲染出的 HTML。
	return arguments.html
}

array function onNav( required array nav, required struct config ) {
	// 修改导航树:由 { title, url, order, children } 节点组成的数组。
	return arguments.nav
}

array function onSearchIndex( required array entries, required struct config ) {
	// 在写入 search-index.json 前修改其条目——每个条目为
	// { title, url, headings, body, tags }。每实际写入一个索引运行一次
	// (主索引 + 每个使用本地索引的版本/语言树)。
	return arguments.entries
}

array function onSitemap( required array pages, required struct config ) {
	// 在 sitemap.xml 与 llms.txt 两者都基于该列表构建之前,修改累计的页面列表。
	// 只有 urlPath/title/hidden 需要设置。
	return arguments.pages
}

void function onBuildComplete( required string siteDir, required struct config ) {
	// 在一切写入 siteDir 之后触发一次。无返回值。
}

}

钩子按 plugins 数组顺序运行;每个钩子的返回值(onBuildComplete 除外)会替换下一个钩子(或 bx-sites 自身)看到的值——如果无需修改,原样返回输入即可。

onPageMarkdown/onPageHtml 针对每个文档树中的每个页面运行一次——包括主 docs/ 树、每个 docs/versions/<name>/ 以及每个 docs/i18n/<code>/(参见 bx-sites-blog-versioning-i18n)。各树是并行渲染的,因此钩子不能依赖各树的构建顺序。

onSearchIndex/onSitemap 存在的意义,是处理完全位于 docs/ 之外的内容(例如 CLI-provider 插件添加的动态服务页面),否则这些内容对搜索/站点地图/llms.txt 不可见。

钩子的调用顺序

onConfig(config) -> 构建导航树 onNav(nav, config) -> 对每个页面:onPageMarkdown(markdown, page, config) -> Markdown() -> onPageHtml(html, page, config) -> 写入 site/ onSearchIndex(entries, config) -> 写入 search-index.json onSitemap(pages, config) -> 写入 sitemap.xml + llms.txt onBuildComplete(siteDir, config)

错误

BxSites.PluginNotFound——plugins 中的某个名称不是已安装/已激活的 BoxLang 模块。

BxSites.InvalidPlugin——模块存在但没有 models/BxSitesPlugin.bx。

注册新的 bxSites CLI 动词(CLI 提供程序)

models/BxSitesPlugin.bx 只覆盖构建生命周期。模块还可以通过同级的 models/BxSitesCliProvider.bx 类注册自己的 bxSites <verb> 命令(例如商业部署/云发布插件),该类只暴露一个 verbs() 方法——同样的 plugins 数组激活方式,不同的文件。一个模块可以实现 BxSitesPlugin.bx、BxSitesCliProvider.bx、两者都实现,或都不实现。

class { struct function verbs() { return { "cloud:publish" : { class : "models.cli.cloud.Publish@myBxSitesAddon", description : "按需构建并通过配置的部署目标发布" } } } }

class { struct function run( struct options ) { // arguments.options 携带与每个核心动词相同的“已解析标志 + projectRoot”结构。 return { exitCode : 0, message : "Published #arguments.options.projectRoot#" } } }

分发类路径上的 @myModuleMapping 后缀是必需的——像 "models.cli.cloud.Publish" 这样的裸点分路径只会相对于 bx-sites 自身的模块根解析;提供程序自己的动词类必须自行附带其模块的 @<mapping> 后缀,否则根本无法被访问。

动词名称是一个用冒号连接的字符串("cloud:publish",与核心用于 post:new/i18n:status 的约定一致);一旦注册了该名称,bxSites cloud publish(两个 argv 词元)和 bxSites cloud:publish 的分发行为完全相同——无需另行注册双词形式。

与内置动词发生名称冲突时核心始终优先(提供程序的条目会被静默忽略——提供程序只能添加命令,永远不能覆盖内置命令)。在两个提供程序之间,plugins 中先列出者优先。

配置缺失/格式错误、没有 BxSitesCliProvider.bx,或 verbs() 抛出异常,都不会破坏核心分发——它们会被当作未激活的插件处理。