Builder.io Cloudinary 图片插件实战:从自定义组件注册到本地开发与发布
2026/9/16 20:50:17 网站建设 项目流程

Builder.io Cloudinary 图片插件实战:从自定义组件注册到本地开发与发布

【免费下载链接】builderVisual Development for React, Vue, Svelte, Qwik, and more项目地址: https://gitcode.com/GitHub_Trending/bu/builder

本篇文章围绕 Builder.io 官方仓库中的 Cloudinary 图片插件(plugins/cloudinary)展开,系统讲解如何将该插件接入 Builder.io Visual Editor、如何通过cloudinaryImageEditor自定义输入类型注册组件并在可视化编辑器中选图,以及如何基于仓库源码理解其底层实现,并完成插件的本地开发、调试与发布。读完本文,你将掌握 Builder.io 插件体系中"自定义编辑器类型"的完整落地套路,并能在自己的项目中直接复刻这一选图体验。

插件能做什么

Builder.io Cloudinary 插件的作用是:让你在 Builder.io 的 Visual Editor(可视化编辑器)中,直接使用 Cloudinary 官方 Media Library(媒体库)组件来访问和管理 Cloudinary 上的图片内容,而不必离开 Builder 的编辑界面、手动拷贝图片 URL。

也就是说,内容编辑者可以在搭建页面时,通过一个标准的 Cloudinary 媒体库弹窗浏览、搜索、选中自己云账号里的图片资产,选中的图片信息(URL、宽高、public_id 等)会被写回到 Builder 内容的字段中,最终由页面组件渲染输出。

插件本身并不直接渲染图片,而是提供一个"编辑器":它注册了一个名为cloudinaryImageEditor的自定义输入类型(custom type),任何在 Builder.io 中注册的自定义组件,只要把某个 input 的类型声明为cloudinaryImageEditor,在 Visual Editor 中编辑该组件时就会自动出现 Cloudinary 选图界面。

安装插件

安装路径在 Builder.io 控制台的Integrations(集成)选项卡中:

  1. 登录 Builder.io 并进入你的 dashboard;
  2. 打开Integrations选项卡;
  3. 在插件列表中找到 Cloudinary 插件,点击Enable(启用)即可。

启用后,插件会在你的 Builder 空间内注册cloudinaryImageEditor这个自定义编辑器类型,接下来就可以在你的 Web 应用里使用它了。

使用插件:注册一个 CloudinaryImage 自定义组件

要在页面中使用 Cloudinary 图片,你需要先注册一个自定义组件,并把它的某个输入类型指定为cloudinaryImageEditor。仓库 README 给出的示例基于@builder.io/react

import { Builder } from '@builder.io/react' Builder.registerComponent( (props) => { if (!props.cloudinaryOptions) { return 'Choose an Image' } return ( <img src={props.cloudinaryOptions.url} width={props.cloudinaryOptions.width} height={props.cloudinaryOptions.height} /> ) }, { name: 'CloudinaryImage', image: 'https://res.cloudinary.com/cloudinary-marketing/image/upload/v1599098500/creative_source/Logo/Cloud%20Glyph/cloudinary_cloud_glyph_blue_png.png', inputs: [{ name: 'cloudinaryOptions', type: 'cloudinaryImageEditor' }], } )

这段代码做了三件事:

  • 注册组件Builder.registerComponentCloudinaryImage注册为一个 Builder 自定义组件;
  • 声明渲染逻辑:组件函数根据props.cloudinaryOptions是否存在决定显示占位文本还是渲染<img>,图片地址、宽高均取自该字段;
  • 绑定编辑器inputs数组中声明cloudinaryOptions字段的类型为cloudinaryImageEditor,这正是插件提供的自定义编辑器类型。

完成注册后,回到 Visual Editor,你会在组件面板中看到名为Cloudinary Image的自定义组件。把它拖拽到内容画布中任意位置,即可通过内嵌的 Cloudinary 媒体库为它选择图片。由于插件基于 Builder 的字段体系工作,选中图片后生成的字段值会随 Builder 内容一起持久化,渲染端无需任何额外逻辑即可直接消费。

字段值的实际形态

从插件源码可以确认,选图后写入字段的是 Cloudinary Media Library 返回的资产对象。插件在 CloudinaryMediaLibraryDialog.tsx 中定义了CloudinaryImage接口:

export interface CloudinaryImage { context: any; public_id: string; url: string; tags: any[]; derived: any[]; }

其中url是图片地址、public_id是资源在 Cloudinary 中的唯一标识、derived通常包含派生(经过变换)版本的 URL 信息、context可携带自定义元数据(如 caption、alt 等)。所以上面示例组件中使用的props.cloudinaryOptions.url.width.height都有明确的字段依据。

第一次使用:认证与选图

首次在 Visual Editor 中使用该组件时,插件会提示你认证 Cloudinary 账号。编辑器界面包含两个按钮,对应两种操作:

SET CREDENTIALS(设置凭据)

点击后弹出凭据设置对话框,需要填写两个字段:

  • API key:Cloudinary 的 API 密钥;
  • Cloud name:Cloudinary 云名称。

需要注意的约束:要让该流程正常工作,你需要在 Builder.io 中启用 SSO 并保持已登录状态——当前版本的插件不支持其他认证方式(源码注释也明确说明"No need to use username for cloudinary login if SSO is enabled")。

凭据只需设置一次。从源码看,凭据保存后会写入组织(organization)级设置:CloudinaryImageEditor.tsx中的 getter/setter 把cloudinaryCloudcloudinaryKey存入this.organization.value.settings.plugins这个 Map,并调用this.organization.save()持久化(见 CloudinaryImageEditor.tsx)。因此同一组织下的编辑会话都无需重复输入凭据,对话框内的 helper 文案也明确写着"You just have to setup the API key once and it will be linked to your organization"。

CHOOSE IMAGE(选择图片)

凭据设置完成后,点击CHOOSE IMAGE会弹出一个 Cloudinary 媒体库浏览器对话框。在媒体库中选中资产后点击INSERT按钮,即可将图片插入页面。

两个关键行为:

  • 每次只能选中一张图片(源码中以multiple: false, max_files: 1配置媒体库,见 CloudinaryMediaLibraryDialog.tsx);
  • 选中图片后,编辑器底部会显示当前选中资源的Public id,方便你确认资源;按钮文案也会从CHOOSE IMAGE变为UPDATE IMAGE,用于替换当前图片(对应 CloudinaryImageEditor.tsx 中的buildChooseImageText逻辑)。

源码级原理:编辑器内部是如何工作的

从源码结构看,插件由三个 React 组件构成,职责非常清晰:

文件职责
CloudinaryImageEditor.tsx主编辑器组件,负责状态管理、凭据读写与按钮渲染,并在文件底部调用Builder.registerEditor({ name: 'cloudinaryImageEditor', component: CloudinaryImageEditor })完成注册
CloudinaryCredentialsDialog.tsx凭据设置对话框,提供 API key 与 Cloud name 两个输入框
CloudinaryMediaLibraryDialog.tsx媒体库对话框,封装 Cloudinary Media Library 组件并处理选图回调

媒体库脚本的加载方式

CloudinaryImageEditorcomponentDidMount阶段会动态向页面注入 Cloudinary 媒体库脚本:

private appendMediaLibraryScriptToPlugin() { const previousScript = document.getElementById('cloudinaryScript'); if (!previousScript) { const script = document.createElement('script'); script.async = true; script.src = `https://media-library.cloudinary.com/global/all.js`; script.id = 'cloudinaryScript'; document.head.appendChild(script); } }

它通过id="cloudinaryScript"做去重,确保脚本只被注入一次;异步加载避免阻塞 Builder 界面。

媒体库的创建与选图回调

CloudinaryMediaLibraryDialog在对话框渲染完成后(onRendered回调)打开媒体库,创建时把组织级凭据传入:

mediaLibrary = newWindow.cloudinary.createMediaLibrary( { cloud_name: this.props.cloudName ? this.props.cloudName : '', api_key: this.props.apiKey ? this.props.apiKey : '', inline_container: '.cloudinaryContainer', }, { insertHandler: (data) => { this.selectImage({ ...data.assets[0] }); }, } );

选中资产后,insertHandler拿到data.assets[0](即第一张选中的图),通过selectImage冒泡给主编辑器,最终由主编辑器调用组件 props 上的onChange,把图片对象写回 Builder 字段。

凭据未设置时的兜底逻辑

主编辑器通过areCloudinaryCredentialsNotSet()判断 API key 或 Cloud name 是否为空;当凭据缺失时,CHOOSE IMAGE按钮会被禁用(disabled属性),并优先展示凭据设置对话框。这一行为在测试中也有覆盖:__tests__/cloudinaryImageEditor.test.tsx验证了"无凭据时选图按钮禁用"以及"凭据写入后 state 被正确更新"。

测试如何保障插件行为

插件附带了一套基于 Jest + Enzyme 的单元测试(位于 plugins/cloudinary/tests),覆盖了三个核心场景:

  • cloudinaryImageEditor.test.tsx:验证无图时按钮显示CHOOSE IMAGE、有图时显示UPDATE IMAGE、底部展示当前Public id、无凭据时按钮禁用、凭据更新后正确回调、有凭据时渲染媒体库对话框、选图后把资产对象传给onChange
  • cloudinaryCredentialsDialog.test.tsx:验证对话框渲染 API key / Cloud name 输入框、输入值写入 state、点击保存时触发updateCloudinaryCredentialscloseDialog回调;
  • cloudinaryMediaLibraryDialog.test.tsx:通过 mockwindow.cloudinary.createMediaLibrary,验证insertHandler会把data.assets[0]作为选中图片、凭据为空时回退为空字符串、点击关闭按钮会触发closeDialog

这些测试很好地展示了"自定义编辑器类型"插件的可测试性:context通过 props 注入、window.cloudinary可 mock,因此几乎不需要真实网络请求就能覆盖关键交互路径。运行测试的命令为:

npm test

插件开发:本地克隆、调试与发布

如果你觉得现成插件不满足需求,想针对自己的使用场景改造它,可以按下面的流程在本地开发。关于 Builder 插件机制的通用说明,可参考仓库内其他插件的组织方式(例如 plugins 目录下各插件均采用类似的src+rollup.config.ts结构)。

1. 安装依赖

git clone https://github.com/BuilderIO/builder.git cd plugins/cloudinary npm install

2. 启动开发服务器

npm start

该脚本(见 package.json 的start字段)会以SERVE=true运行 rollup 的 watch 模式,并在1268 端口启动一个静态服务器。从 rollup.config.ts 可以看到,这个开发服务器配置了Access-Control-Allow-Origin: *Access-Control-Allow-Private-Network: true响应头,以便本地开发时被 Builder 的 https 页面跨域加载。

3. 把开发版插件挂到 Builder.io

  1. 进入你的 Account Settings(账户设置)页面;
  2. 点击Plugins旁边的编辑(铅笔)按钮;
  3. 输入开发版插件的 URL,例如http://localhost:1268/builder-plugin-cloudinary.system.js
  4. 保存。

builder-plugin-cloudinary.system.js对应 package.json 中声明的main/unpkg产物,由 rollup 以 SystemJS 格式(UMD、ES 与 System 三种格式同时产出)打包生成。

注意:在 https 站点上加载 http 内容会触发混合内容警告。本地开发时需要点击浏览器右上角的盾牌图标,选择"加载不安全脚本"(load unsafe scripts),允许 Builder 的 https 页面加载本地 http 资源。

之后每当你修改源码并重新构建,重启 Builder 即可看到插件的最新版本。

4. 卸载开发版插件

回到 Account Settings,点击Plugins旁的编辑按钮,从列表中删除你的开发 URL 并保存即可。

5. 技术栈与发布

插件的 UI 技术栈与 Builder 本身保持一致:

  • React:组件框架;
  • Material UI:对话框、按钮、文本输入等界面组件(源码中大量使用@material-ui/coreDialogButtonTextFieldTypography);
  • Emotion:CSS-in-JS 样式方案(源码中的css={...}属性均来自@emotion/core)。

在 Builder 插件中使用这些框架可以保证最佳的体验与性能。注意 rollup.config.ts 中把react@builder.io/sdk@material-ui/core@emotion/core等声明为external,注释说明插件必须与宿主页面共享这些依赖的同一份引用才能正常运行——这是开发 Builder 插件时的关键约束。

如果你认为自己的插件对 Builder 社区有复用价值,可以给本仓库提交 Pull Request,维护者会进行评审。否则,当插件准备好后,你也可以发布 npm 包,并把打包后的 JS 链接添加到Account Settings > Plugins中(该入口仅对企业版用户开放)。

小结

Builder.io Cloudinary 插件是理解 Builder 插件体系的一个极佳范例:它通过Builder.registerEditor暴露自定义输入类型,借助组织级 settings 持久化凭据,再以官方 Media Library 组件提供选图体验。对于要在 Builder 内容中接入任意外部素材库(图片、视频、文档等)的开发者而言,本文介绍的自定义编辑器模式可以直接迁移复用;仓库内的源码与测试则为二次开发提供了完整且可验证的参考实现。

【免费下载链接】builderVisual Development for React, Vue, Svelte, Qwik, and more项目地址: https://gitcode.com/GitHub_Trending/bu/builder

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询