插件可以向 Portable Text 编辑器添加自定义块类型 —— YouTube 嵌入、代码片段、图片库,以及默认块集合未涵盖的任何内容。沙盒插件可以声明这些块的编辑 UI(使用 Block Kit 字段),但在公共网站上渲染它们的 Astro 组件必须在构建时从 npm 加载。这就是需要原生插件的部分。
如果您的插件只需要编辑侧字段,并且有其他人提供渲染组件(或网站在本地提供),您可以保持沙盒状态。如果插件也需要提供渲染组件,则需要使用原生插件。
声明块类型
沙盒插件和原生插件都可以声明块类型。原生插件在 definePlugin() 内的 admin.portableTextBlocks 下执行此操作:
admin: {
portableTextBlocks: [
{
type: "youtube",
label: "YouTube Video",
icon: "video", // video, code, link, link-external
placeholder: "Paste YouTube URL...",
fields: [ // Block Kit fields for the editing UI
{ type: "text_input", action_id: "id", label: "YouTube URL" },
{ type: "text_input", action_id: "title", label: "Title" },
{ type: "text_input", action_id: "poster", label: "Poster Image URL" },
],
},
],
},
每个块类型定义:
type— 块类型名称(在 Portable Text 的_type中使用)。label— 在编辑器的斜杠命令菜单中显示的名称。icon—video、code、link或link-external。默认回退到通用立方体。placeholder— 输入占位符文本。fields— 用于编辑的 Block Kit 表单字段。如果省略,将显示简单的 URL 输入。
在公共网站上渲染
要在公共网站上渲染块类型,请从 componentsEntry 导出 Astro 组件。导出名称必须是 blockComponents:
import YouTube from "./YouTube.astro";
import CodePen from "./CodePen.astro";
export const blockComponents = {
youtube: YouTube,
codepen: CodePen,
};
在描述符上设置 componentsEntry:
export function myPlugin(): PluginDescriptor {
return {
id: "embeds",
version: "1.0.0",
format: "native",
entrypoint: "@my-org/embeds",
componentsEntry: "@my-org/embeds/astro",
};
}
EmDash 会自动将插件块组件合并到 <PortableText> 中 —— 网站作者无需导入任何内容。用户提供的组件(在网站的 <PortableText> 的 components 属性中声明)优先于插件默认值。
包导出
将 ./astro 导出添加到 package.json:
{
"exports": {
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
"./admin": { "types": "./dist/admin.d.ts", "import": "./dist/admin.js" },
"./astro": { "types": "./dist/astro/index.d.ts", "import": "./dist/astro/index.js" }
}
}
./astro 导出是服务器端的(Astro SSR),./admin 导出是浏览器端的(React),"." 导出是描述符 + createPlugin。将它们保存在单独的文件中,因为它们针对不同的环境进行打包。
沙盒友好的变体
如果您希望插件是沙盒的,但仍然提供默认的渲染体验,通常的模式是:
- 在市场上发布沙盒插件(仅编辑字段)。
- 在 npm 上发布单独的配套原生包,提供 Astro 渲染组件。
- 记录两者:最终用户从市场安装沙盒插件,并通过
npm install安装配套包进行渲染。
这将一步安装换成了保持编辑器侧沙盒化。当涉及块渲染时,完全原生更简单,但这种拆分仍然是一个选项。