Builder.io Swell 插件实战指南:把 Swell 商品与集合数据无缝接入 Builder.io 内容平台
【免费下载链接】builderVisual Development for React, Vue, Svelte, Qwik, and more项目地址: https://gitcode.com/GitHub_Trending/bu/builder
本文围绕 Builder.io 官方开源仓库中的plugins/swell插件,讲解如何将 Swell 电商平台的商品(Product)与集合(Collection)数据接入 Builder.io 的内容编辑与个性化体系。你将掌握插件的安装与鉴权方式、六种新增字段类型在自定义定向(Custom Targeting)、组件模型字段(Component Model Fields)与符号输入(Symbol Inputs)三种场景下的用法,理解字段值如何被自动解析为 Builder.ioRequest对象,并学会本地开发、调试与发布该插件。
插件定位:为 Builder.io 打开 Swell 数据通道
Swell 是一个 API 优先的电商平台(headless commerce),商品、分类、订单等数据都通过 REST/GraphQL API 暴露。plugins/swell插件的核心目标正如其 README 所述:"Easily connect your Swell data to your Builder.io content!",即让内容编辑者在 Builder.io 的模型(Model)、符号(Symbol)和自定义组件(Custom Component)中,直接搜索、选择 Swell 商品或集合,并把选中结果作为字段值写入内容。
插件本质是一个 Builder.io 平台插件(Plugin),通过 Builder 提供的插件注册机制动态扩展编辑器的字段类型与定向能力。在 plugins/swell/src/plugin.ts 中,插件调用@builder.io/commerce-plugin-tools提供的registerCommercePlugin完成注册:
import { registerCommercePlugin } from '@builder.io/commerce-plugin-tools'; import swell from 'swell-js'; registerCommercePlugin( { name: 'Swell', // should always match package.json package name id: '@builder.io/plugin-swell', ... }, async settings => { ... } );registerCommercePlugin是 Builder.io 为电商类插件提供的一站式基座(同一机制被 plugins/shopify/src/plugin.ts、plugins/bigcommerce/src/plugin.ts、plugins/vtex/src/plugin.ts 等大量电商插件复用),它约定了product与category两组统一资源接口(findById、findByHandle、search、getRequestObject)。Swell 插件只需按此契约实现 Swell API 的适配,即可自动获得 Builder 编辑器中的搜索弹窗、字段解析与定向能力。
安装插件与鉴权配置
安装插件在 Builder.io 后台完成,无需改动任何前端代码:
- 登录后进入Account > Organization(对应 README 中的 builder.io/account/organization)页面;
- 在插件列表中选中
@builder.io/plugin-swell; - 点击保存(Save),此时系统会提示输入 Swell 商店的连接凭据。
凭据部分需要注意 README 与源码的一处差异:README 安装段落写作"you'll be prompted for storeId and secretKey",而插件实际注册的配置项(见 plugins/swell/src/plugin.ts)是storeId与publicKey两个必填项,helperText 明确指示从 Swell 商店设置的 API Keys > Public api key 中获取:
settings: [ { name: 'storeId', type: 'string', required: true, helperText: 'Get your Store ID from swell store settings https://swell.store/docs/api/?javascript#authentication', }, { name: 'publicKey', type: 'string', required: true, helperText: 'Get your Public key from swell store settings > API keys > Public api key https://swell.store/docs/api/?javascript#authentication', }, ], ctaText: `Connect your swell.is store`,连接按钮文案为 "Connect your swell.is store"。鉴权完成后,插件会执行swell.init(storeId, publicKey)(见 plugins/swell/src/plugin.ts)初始化swell-js客户端。需要说明:storeId 与 publicKey 都是公开信息(public key 仅用于只读的 storefront 请求),因此可以安全地以明文形式出现在前端插件中;如果后续需要写入订单等敏感操作,则应使用服务端密钥(secret key)而非该 publicKey。
安装成功后,编辑器中将出现六种新的字段类型,它们分别适用于三种上下文:自定义定向属性、组件模型字段与符号输入。下表是六种字段类型的速览:
| 字段类型 | 适用上下文 | 作用 |
|---|---|---|
Swell Product | 自定义定向 / 符号输入 | 按商品 ID 定向或搜索选择商品 |
Swell Product Handle | 自定义定向 | 按商品 handle(slug)定向 |
Swell Collection | 自定义定向 / 符号输入 | 按集合 ID 定向或搜索选择集合 |
Swell Collection Handle | 自定义定向 | 按集合 handle(slug)定向 |
Swell Product Preview | 组件模型字段 | 动态拼接商品模板的预览 URL |
Swell Collection Preview | 组件模型字段 | 动态拼接集合模板的预览 URL |
场景一:自定义定向(Custom Targeting)
Builder.io 的自定义定向允许内容按任意属性(attribute)做细分投放。Swell 插件将商品与集合扩展为可用的定向类型:当某个内容条目设置了Swell Product类型的目标属性时,只有访问上下文中携带了对应商品 ID 的用户才会命中该内容。
要让服务端渲染(SSR)或客户端渲染(CSR)正确识别,需要先在宿主站点设置目标属性。客户端渲染场景下,使用builder.setUserAttributes设置当前上下文(见 plugins/swell/src/plugin.ts 对应的 README 示例):
builder.setUserAttributes({ product: currentProduct.id, });服务端场景下,则把用户属性作为查询参数传给内容 API(Query API 的userAttributes参数),或在 Gatsby、Next.js 中通过 GraphQL API 的 targeting 参数传入。例如通过 Query API 请求时大致形态为:
// https://cdn.builder.io/api/v1/html/page?...&userAttributes.product=<productId>各字段类型的定向语义如下:
Swell Product:定向到"字段值等于商品 ID"的上下文。需要在宿主环境用上述任一方法设置当前商品 ID;Swell Product Handle:若希望按商品的 handle(即 URL slug)而不是数字 ID 定向,改用此类型。宿主环境设置builder.setUserAttributes({ product: currentProduct.handle })即可;Swell Collection:定向到特定集合,按集合 ID 匹配,宿主环境需设置集合 ID;Swell Collection Handle:按集合 handle 定向,适合以语义化 slug 做匹配的场景。
从源码角度看,ID 与 handle 的解析分别由插件暴露的findById与findByHandle完成(见 plugins/swell/src/plugin.ts),二者都调用swell.products.get(id | handle)——Swell API 允许以 ID 或 slug 直接读取资源:
async findById(id: string) { const product = await swell.products.get(id); return transformResource(product); }, async findByHandle(handle: string) { const product = await swell.products.get(handle); return transformResource(product); },场景二:组件模型字段(Component Model Fields)
组件模型(Component Model)通常用于表达"商品页模板"或"集合页模板",可作用于全部或某一组商品/集合。为了让内容编辑者在编辑器中实时预览任意商品/集合对应的模板页面,插件提供了两个预览字段:
Swell Product Preview
在组件模型上添加类型为Swell Product Preview的自定义字段,并给模型配置带变量的模板编辑 URL,例如:
https://www.mystore.com/product/${previewProduct.handle}此后创建新的内容条目时,Builder 会基于"当前预览的商品"动态地把 handle 填入 URL。官方建议为该字段设置默认值,这样开发者进入模板组件开发时能直接落在某个具体的商品页,而不是空 URL。
Swell Collection Preview
用法与 Product Preview 完全对称:给模型添加Swell Collection Preview字段,并把模型 URL 配置为集合模板,例如:
https://www.mystore.com/collection/${previewCollection.handle}创建条目后,handle 会基于预览集合动态填充。同样建议为字段设置默认值,保证开发时稳定落在某个集合页。
这两个字段依赖插件在transformResource(见 plugins/swell/src/plugin.ts)中返回的handle字段(取自 Swell 资源的slug),因此模型 URL 中可以直接引用${previewProduct.handle}/${previewCollection.handle}这样的插值:
const transformResource = (resource: any) => ({ id: resource.id, title: resource.name, handle: resource.slug, ...(resource.images && { image: { src: resource.images[0]?.file.url, }, }), });场景三:符号输入(Symbol Inputs)与 Request 对象解析
当把Swell Product或Swell Collection用作符号(Symbol)输入字段时,编辑器中的 UI 会弹出搜索框,允许按关键字搜索 Swell 商品/集合。搜索由插件的search方法实现(见 plugins/swell/src/plugin.ts),通过swell.products.list/swell.categories.list拉取结果,并注明"如需分页可扩展 limit/page":
async search(search: string) { const response = await swell.products.list({ search, // TODO: pagination if needed limit: 100, page: 1, }); return response.results.map(transformResource); },关键在于值形态:当字段被 API、SDK 或 Builder 编辑器消费时,选中的商品/集合不会被存成普通字符串,而是被自动解析为一个 Builder.io 标准的Request对象:
{ "yourFieldName": { "@type": "@builder.io/core:Request", "request": { "url": "..." }, "data": { "product": { "/* ... */" } } } }这个对象由插件的getRequestObject方法生成(见 plugins/swell/src/plugin.ts),URL 拼接规则为https://{publicKey}@{storeId}.swell.store/api/products/{id}(分类同理为/api/categories/{id}):
getRequestObject(id: string) { return { '@type': '@builder.io/core:Request' as const, request: { url: `https://${publicKey}@${storeId}.swell.store/api/products/${id}`, }, options: { product: id, }, }; },理解这一设计对内容架构很重要:Request对象是 Builder.io 的"延迟取数"机制——字段里只保存请求描述(URL),真正拉取响应数据发生在渲染阶段;data中的product/category是请求完成后填充的响应内容。因此内容条目天然携带"可重放"的数据请求,既能在编辑器里预览,也能在 SSR/CSR 阶段由 Builder SDK 自动请求并注入,避免把易过期的商品快照硬编码进内容。
本地开发:把插件跑起来
plugins/swell是仓库中独立的可开发插件包(npm 包名为@builder.io/plugin-swell,版本见 plugins/swell/package.json),本地开发流程如下:
1. 安装依赖
git clone <本仓库地址> cd plugins/swell npm install2. 启动开发服务器
npm start该命令等价于SERVE=true rollup -c rollup.config.ts -w(见 plugins/swell/package.json)。Rollup 的 serve 插件会在1268 端口托管dist目录下的构建产物(见 plugins/swell/rollup.config.ts),并附带Access-Control-Allow-Origin: *与Access-Control-Allow-Private-Network响应头,以兼容浏览器私有网络访问(PNA)预检。
3. 把本地插件接入 Builder.io
回到 Account > Organization 的插件设置页,把本地地址填入插件配置:
http://localhost:1268/plugin.system.js?pluginId=@builder.io/ecom-swell-is注意:Builder.io 后台是 https 站点,而本地开发地址是 http。浏览器会阻止混入的不安全脚本,需要在页面右上角点击盾牌图标并选择 "Load unsafe scripts"(加载不安全脚本)才能正常加载本地插件。每次修改源码后重启 Builder 页面即可看到最新版本;要卸载插件,直接在插件管理 UI 中移除即可。
4. 验证插件效果
创建一个自定义模型、自定义组件或符号,在其中添加 Swell 类型字段即可编辑验证。例如给模型加一个Swell Product字段,编辑器里应出现商品搜索弹窗,选中后字段值显示为商品卡片(含图片、标题、handle)。
5. 构建与发布
生产构建命令为npm run build(先rimraf dist清理,再tsc+rollup打包,见 plugins/swell/package.json)。产物入口为dist/plugin.system.js(SystemJS 格式,见 plugins/swell/rollup.config.ts)。插件发布走语义化版本:npm run release:dev打 dev 预发布版本用于联调,合并 PR 后npm run release:patch发布补丁版本(发布与测试流程详见 plugins/README.md)。仓库还配置了 jest 测试与 90% 以上的覆盖率门槛(见 plugins/swell/package.json),为插件行为提供回归保障。
插件 UI 技术栈与最佳实践
Builder.io 插件体系的 UI 统一基于React与Material UI,样式使用Emotion(见 README 的 Frameworks 小节,以及 plugins/swell/package.json 中的react、@material-ui/core、@emotion/core依赖)。插件与宿主共享这些运行时,因此 Rollup 配置将这些包显式列入external(见 plugins/swell/rollup.config.ts),避免重复打包导致 React 多实例问题:
external: [ 'react', '@builder.io/react', '@builder.io/app-context', '@material-ui/core', '@emotion/core', '@emotion/styled', 'mobx', 'react-dom', 'mobx-react', ],注释明确提示:不要改动这份 external 列表,新增依赖也应保持不被打包,这是插件在 Builder 编辑器内稳定运行的前提。
开发插件时遵循这一约定,配合@builder.io/commerce-plugin-tools的product/category资源契约,即可用极少的代码让任意电商后端接入 Builder.io——这正是plugins/swell这份实现(完整源码仅一个 plugin.ts 文件)所展示的典型范式。
【免费下载链接】builderVisual Development for React, Vue, Svelte, Qwik, and more项目地址: https://gitcode.com/GitHub_Trending/bu/builder
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考