用 Gadget 开发 Shopify Extension-only App:从零创建 Admin Block 扩展

文章目录

如果你的 Shopify App 不需要独立的商品管理页面,而是只需要在 Shopify Admin 的某个位置显示一个小功能,那么可以使用 Extension-only App。

这类应用不需要自己搭建完整的前端网站,应用的主要功能通过 Shopify Extension 显示在指定位置,例如:

  • 商品详情页
  • 订单详情页
  • 客户详情页
  • Shopify Admin 的其他支持位置

本文会演示如何:

  • 使用 Shopify CLI 创建 Extension-only App
  • 创建一个 Admin Block 扩展
  • 使用 Gadget 管理 Shopify 连接和后端
  • 配置 API 权限
  • 将 Gadget 和 Shopify App 连接起来
  • 在 Development Store 中测试扩展
  • 通过 Shopify CLI 发布扩展

需要特别注意的是:

本文适用于从零创建新的 Extension-only Shopify App。
如果你已经有一个手动创建并连接到 Gadget 的 Shopify App,不需要重新创建应用,可以直接按照“为现有 Gadget 应用添加 Extension”的流程操作。

Extension-only App 是什么?

传统 Shopify App 通常包含:

Shopify App
├── Embedded Admin 页面
├── 后端服务
├── 数据库
└── Shopify Extension

Extension-only App 可以简化为:

Shopify App
└── Shopify Extension

在本文的开发方式中,Extension 代码由 Shopify CLI 管理,Gadget 负责:

  • Shopify Connection
  • OAuth
  • API 权限连接
  • 后端服务
  • 数据库
  • Embedded Admin 页面
  • 商店安装关系

整体结构如下:

Shopify Dev Dashboard
        ↓
Shopify App 身份和版本
        ↓
Shopify CLI Extension
        ↓
Admin Block
        ↓
Gadget Shopify Connection
        ↓
Gadget 后端和数据库

Shopify 从 Summer ’23 开始支持 Extension-only App,适合只需要创建 Checkout、Admin 或其他扩展功能的应用。citation:Shopify Editions Summer ’23

什么时候适合使用 Extension-only App?

Extension-only App 适合以下场景:

  • 在商品页面增加一个管理区块
  • 在订单页面显示外部系统状态
  • 在客户页面显示会员信息
  • 在 Checkout 中显示应用内容
  • 在后台页面增加快捷操作
  • 只需要 Shopify 原生页面中的一个小功能

如果应用需要复杂的独立管理后台,例如:

  • 商品批量处理
  • 订单报表
  • 复杂配置
  • 多页面导航
  • 商家设置中心
  • 数据分析面板

那么通常应该使用完整的 Embedded App,再将 Extension 作为其中的一部分。

开始前的准备

开始前需要准备:

  • Shopify Partners 或开发者账号
  • Shopify CLI
  • 一个 Shopify Development Store
  • 一个 Gadget 账号
  • Node.js 和包管理工具
  • 一个代码编辑器,例如 VS Code

建议使用 Development Store 测试应用,不要直接连接真实商店。

开发商店可以用于:

  • 安装应用
  • 测试 Admin Extension
  • 测试 API 权限
  • 调试 Gadget 连接
  • 测试应用版本发布

Shopify 当前建议使用 Dev Dashboard 管理应用,并使用 Shopify CLI 创建和开发应用。Dev Store 专门用于应用测试,不会影响正式商店。citation:Building apps

创建 Extension-only Shopify App

打开终端,使用当前版本的 Shopify CLI 创建应用。

不同版本的 CLI 命令可能不同,可以使用 Shopify CLI 的应用创建向导:

Create Shopify app

创建时选择:

Extension-only app

不要选择:

Remix app

原因是 Gadget 会负责嵌入式 Admin 应用和后端。如果这里再创建一个完整 Remix App,就可能出现两个前端入口:

Shopify CLI Remix App
Gadget Embedded App

这会增加 OAuth、URL 和部署配置的复杂度。

项目名称可以设置为:

admin-extension-app

创建完成后,进入项目目录:

cd admin-extension-app

使用 VS Code 或其他代码编辑器打开项目。

Extension-only 项目通常会比较精简,主要包含:

  • shopify.app.toml
  • extensions/
  • 包管理文件
  • Shopify CLI 配置
  • Extension 源代码

创建第一个 Admin Block

在项目目录中运行 Shopify CLI 的 Extension 生成命令。

当前 CLI 通常会提供类似的生成入口:

Generate extension

选择:

Admin block

然后填写扩展名称:

admin-block

语言可以选择:

JavaScript

或:

TypeScript

生成完成后,项目中通常会出现:

extensions/admin-block

其中包括:

shopify.extension.toml
src/

shopify.extension.toml 用来定义:

  • Extension 类型
  • Extension target
  • 名称
  • 权限和能力
  • 构建入口
  • 发布配置

src/ 目录存放 Admin Block 的界面代码。

理解 Shopify App 配置文件

项目根目录的:

shopify.app.toml

用于管理 Shopify App 配置。

其中可能包含:

  • 应用名称
  • 应用 URL
  • OAuth 回调地址
  • API Scopes
  • Webhook API 版本
  • 应用版本配置
  • 安装流程配置
  • Extension 相关设置

如果使用 Gadget 管理 Shopify Connection,权限和安装流程可能由 Gadget 连接配置负责。

因此,在修改 shopify.app.toml 前,需要确认:

哪些配置由 Shopify CLI 管理?
哪些配置由 Gadget 管理?

不要让 Shopify CLI 和 Gadget 同时管理同一组互相冲突的权限或安装配置。

为 Gadget 启用兼容的安装流程

Extension-only App 本身可能没有完整的嵌入式网页入口,但 Gadget 需要处理:

  • 应用安装
  • OAuth
  • Shopify Session Token
  • 商店连接
  • Access Token
  • Embedded Admin 页面

在使用 Gadget 连接 Extension-only App 时,可能需要在 shopify.app.toml 中启用 Gadget 所要求的安装流程配置。

例如某些 Gadget 工作流会使用:

use_legacy_install_flow = true

这个配置应该根据当前 Gadget 集成文档和 Shopify CLI 版本确认。

启用后,需要将配置推送到 Shopify App:

shopify app config push

执行时,CLI 通常会显示配置变化预览。确认修改内容正确后再提交。

重点检查:

  • 修改的是正确的 Shopify App
  • 没有覆盖错误环境
  • Development App 和 Production App 没有混用
  • Gadget 连接使用的是同一个 Shopify App

启动 Extension 进行第一次测试

在项目目录运行 Shopify CLI 的开发命令。

不同版本的项目可能使用:

shopify app dev

或者项目生成的包管理脚本:

yarn dev

运行后:

  1. 选择 Shopify Partners 组织
  2. 选择 Development Store
  3. 生成开发预览地址
  4. 安装或更新应用
  5. 打开 Shopify Admin
  6. 进入扩展对应的页面
  7. 检查 Admin Block 是否显示

第一次测试时,建议先不要接入复杂业务逻辑,只显示一段简单文字:

Admin Block is working

如果这段文字可以显示,说明以下部分基本正常:

  • Shopify App 创建成功
  • Extension 生成成功
  • CLI 开发服务正常
  • Development Store 连接正常
  • Extension target 配置正确

在 Shopify Admin 中查看 Admin Block

如果扩展的目标是商品页面,可以打开:

Products → 选择一个商品

然后在页面中寻找:

Apps
App blocks
Add block

具体显示位置取决于 Extension target 和当前 Shopify Admin 版本。

如果看不到扩展,检查:

  • Extension 是否正在运行
  • 应用是否安装到当前商店
  • 当前页面是否支持该 Extension target
  • 使用的 Development Store 是否正确
  • 是否安装了最新应用版本
  • Extension 名称是否正确

Admin Extension 的显示位置和可配置方式取决于目标页面。不要假设所有 Extension 都会出现在同一个位置。

创建 Gadget 应用

接下来创建 Gadget 项目。

在 Gadget 中选择:

Shopify App

应用名称可以设置为:

Admin Extension App

Gadget 会创建:

  • PostgreSQL 数据库
  • Node.js 后端
  • React 前端
  • Shopify Connection
  • API 客户端
  • Development 环境
  • Production 环境

这里的 Gadget 应用负责管理应用逻辑和商店数据。

Extension-only 不代表应用不能有后台。它只是表示 Shopify CLI 项目本身不再创建一个独立的 Remix App。

将 Shopify App 连接到 Gadget

进入 Gadget 的 Shopify Connection 设置。

从 Shopify Dev Dashboard 或 Partner 应用配置中复制:

Client ID
Client Secret

粘贴到 Gadget 的 Shopify Connection。

然后选择项目需要的数据和权限。

本示例选择:

read_products
Shopify Product

这样 Gadget 可以:

  • 读取 Shopify 商品
  • 将商品同步到数据库
  • 为商品数据生成模型
  • 提供商品 API
  • 注册商品 Webhook

连接完成后,Gadget 通常还会生成:

  • Shopify Product
  • Shopify Shop
  • Shopify Sync
  • GDPR Request

配置 App URL 和回调地址

从 Gadget Shopify Connection 页面复制:

App URL
OAuth Callback URL

回到 Shopify App 配置中,将它们分别填入:

App URL
Allowed redirection URL

检查:

  • App URL 没有填成回调地址
  • OAuth 回调路径完整
  • 使用 HTTPS
  • 没有混用 Development 和 Production 地址
  • Gadget 使用的 Client ID 与 Shopify App 相同
  • 当前应用配置已经保存并发布

如果 App URL 或回调地址错误,常见结果是:

  • 安装后跳转失败
  • 页面显示 Not Found
  • OAuth 无限循环
  • 应用无法嵌入 Shopify Admin

重新安装或更新应用

当新增 API Scope 或修改应用安装配置后,原来的安装可能不会立即获得新配置。

可以在 Shopify App 的 Development Store 安装页面中重新安装或更新应用。

更新时重点检查:

  • 新权限是否出现在授权页面
  • 应用是否能正常打开
  • Gadget 是否显示已连接
  • Shop 记录是否存在
  • Extension 是否仍然能够加载

如果只是修改 Extension 前端代码,通常只需要重新运行开发预览。如果修改了 API 权限、App URL 或应用版本,则需要更新应用配置并重新安装或发布版本。

执行商品数据同步

如果 Gadget 连接了 Shopify Product 模型,可以执行历史商品同步。

在 Gadget 的 Shopify Connection 或 Installs 页面中,找到类似:

Sync
Start sync
Historical sync
Data sync

执行同步后,Gadget 会将 Development Store 中的商品导入数据库。

检查:

  • 商品记录是否出现
  • 商品标题是否正确
  • 商品 ID 是否正确
  • 商品数量是否合理
  • 同步是否完成
  • 是否存在失败记录

商品同步和 Extension 本身是两个不同部分:

Extension 负责显示功能
Gadget 负责数据和后端逻辑

如果 Admin Block 只是显示固定内容,不需要商品数据。但如果要显示商品、订单或商店配置,就需要通过 Gadget API 或 Shopify API 获取数据。

在 Gadget 中开发后端逻辑

Gadget 会根据模型自动生成数据 API。

如果需要自定义功能,可以创建:

Custom Action

例如:

saveSelectedProduct

这个 Action 可以负责:

  • 保存商家选择的商品
  • 写入 Shop Metafield
  • 读取当前商店
  • 验证商品属于当前商店
  • 记录操作日志

Action 参数可以包括:

shopId
productId

在公开应用中,要特别注意多租户数据隔离:

当前商店请求
        ↓
验证当前商店身份
        ↓
只读取当前商店的数据
        ↓
拒绝访问其他商店的数据

不能只相信前端传入的 shopId。

配置 Gadget Access Control

Gadget 新建的模型和 Action,默认可能不会开放给 Shopify 商家用户。

在 Access Control 中,为 Shopify App Users 角色开放需要的权限。

例如:

Read Shop
Update Shop
Run saveSelectedProduct

如果没有配置,前端可能出现:

Permission denied

检查顺序:

  1. Action 是否已经创建
  2. Action 是否允许 API 调用
  3. Shopify App Users 是否拥有执行权限
  4. 当前商店是否已经安装应用
  5. 当前 Shop 记录是否属于当前商店

将 Gadget 前端嵌入 Shopify Admin

Gadget 可以提供一个嵌入 Shopify Admin 的 React 页面。

这个页面可以用于:

  • 显示当前商店信息
  • 显示商品列表
  • 保存应用设置
  • 显示同步状态
  • 触发后台 Action
  • 管理 Extension 的配置

如果 Extension 需要商家先选择商品,可以在 Gadget Admin 页面中实现:

读取商品列表
        ↓
商家选择一个商品
        ↓
点击 Save
        ↓
调用 Gadget Action
        ↓
保存商店配置

Extension 只负责在 Shopify 的指定位置显示内容,复杂的商家配置仍然适合放在 Gadget 的 Embedded App 中。

管理项目代码和 Extension

如果使用 Gadget CLI 和本地开发,建议将以下内容放在同一个代码仓库中:

  • Gadget 后端
  • Gadget React 页面
  • Shopify Extension
  • Shopify App 配置
  • 部署配置

Extension 的构建目录和依赖目录不应该重复同步到 Gadget 项目。

可以使用类似 .gadgetignore 的忽略配置排除:

node_modules
extensions/*/dist
build
缓存目录
临时文件

具体格式以当前 Gadget CLI 生成的项目为准。

这样做的好处是:

一个代码仓库
    ↓
Gadget 后端
Gadget 前端
Shopify Extension
应用配置
版本管理

团队可以通过 Git 管理完整应用,而不是分别维护多个目录。

本地修改 Extension

修改 Extension 的源代码后,保持 Shopify CLI 开发命令运行。

如果 Gadget CLI 也在运行,则:

  • Gadget 编辑器中的修改可以同步到本地
  • 本地代码修改可以同步回 Gadget
  • Extension 代码可以单独由 Shopify CLI 构建和预览

第一次开发时建议从最简单的 UI 开始:

显示一个文本区块
显示一个按钮
显示当前页面资源 ID

确认 Extension 可以正常加载后,再接入:

  • Gadget API
  • Shop 配置
  • Shopify Admin API
  • 外部服务
  • 商店数据

发布 Extension

开发完成后,使用当前 Shopify CLI 项目提供的部署命令发布 Extension。

常见流程是:

构建 Extension
        ↓
检查配置
        ↓
上传 Extension
        ↓
创建新的 App Version
        ↓
发布 App Version
        ↓
在 Development Store 中验证

部分项目会使用:

shopify app deploy

具体命令以当前 Shopify CLI 项目输出为准。

部署时要确认:

  • 发布的是正确的 Shopify App
  • 发布的是正确的环境
  • Extension target 没有改错
  • 应用版本包含最新 Extension
  • Gadget 连接使用的是同一个 Shopify App

测试 Extension-only App

建议按照以下顺序测试。

测试应用安装

  • Development Store 能打开安装流程
  • OAuth 可以完成
  • 应用不会无限跳转
  • Gadget 中出现 Shop 记录
  • App URL 和回调地址正确

测试 Admin Block

  • 商品页面可以打开
  • Apps 或 App Block 区域能看到扩展
  • 扩展可以正常渲染
  • 刷新页面后仍然显示
  • 窄屏页面没有明显布局问题

测试 Gadget 后端

  • Shopify Product 可以同步
  • Shop 记录可以读取
  • 自定义 Action 可以执行
  • Access Control 没有拒绝错误
  • Gadget 日志没有敏感信息

测试应用更新

  • 修改 API Scope 后可以重新授权
  • 修改 Extension 后可以发布新版本
  • 已安装商店可以更新应用
  • 旧版本没有影响生产环境

部署到 Production

Development 测试完成后,再部署到 Production。

生产环境建议使用独立的:

  • Shopify Production App
  • Gadget Production 环境
  • Client ID
  • Client Secret
  • App URL
  • OAuth 回调地址
  • 数据库
  • 环境变量

部署顺序如下:

Development 测试完成
        ↓
发布 Shopify Extension 版本
        ↓
部署 Gadget Production
        ↓
配置 Production URL
        ↓
安装到目标商店
        ↓
测试 Extension
        ↓
检查日志和数据

生产环境中需要再次确认:

  • Shopify App 与 Gadget Production 使用相同配置
  • Client ID 和 Client Secret 没有混用
  • Extension 发布到了正确的 App
  • Gadget 数据库使用的是生产环境
  • Admin Block 在目标页面可用
  • 目标商店套餐支持该 Extension

常见问题排查

Extension 可以运行,但 Gadget 应用打不开

检查:

  • Gadget App URL 是否配置正确
  • OAuth 回调地址是否完整
  • Client ID 是否属于当前 Shopify App
  • Shopify App 是否已经发布配置
  • 当前商店是否安装了最新应用版本

安装后显示 Not Found

检查:

  • App URL 是否填错
  • 使用的是否是 Development URL
  • Gadget 应用是否正在运行
  • OAuth 回调地址是否漏掉路径
  • 当前 Shopify App 是否连接到了正确的 Gadget 项目

Admin Block 没有显示

检查:

  • Extension 是否已经生成
  • Extension 是否已经部署
  • target 是否支持当前 Admin 页面
  • 当前应用是否安装到正确商店
  • 是否需要在 Admin 页面手动添加 App Block
  • 是否使用了正确的 App Version

API Scope 没有生效

检查:

  • 是否在 Shopify App 配置中声明 Scope
  • 是否在 Gadget Shopify Connection 中选择 Scope
  • 是否推送并发布了新版本
  • 是否重新安装或更新了应用
  • 当前商店是否同意了新权限

Gadget 中出现 Permission denied

检查:

  • Shopify App Users 是否有模型读取权限
  • 自定义 Action 是否开放执行权限
  • 当前用户是否属于正确角色
  • 当前 Shop 是否属于当前商店
  • 前端是否调用了正确的 API

本地修改没有同步

检查:

  • Gadget CLI 是否正在运行
  • Shopify CLI 是否正在运行
  • 当前目录是否是正确项目
  • Extension 是否被 .gadgetignore 排除
  • 是否修改了构建目录而不是源代码目录
  • 浏览器是否需要刷新

项目验收清单

完成以下检查后,Extension-only App 才算真正跑通:

  • Shopify CLI 能创建 Extension-only App
  • Admin Block 能够成功生成
  • Extension 可以安装到 Development Store
  • Gadget Shopify Connection 正常
  • OAuth 安装流程正常
  • App URL 和回调地址正确
  • Shopify Product 数据可以同步
  • Shop 记录可以创建和读取
  • Shopify App Users 拥有正确权限
  • 自定义 Action 可以执行
  • Extension 可以渲染
  • Admin 页面可以看到 Extension
  • 应用更新后 Extension 仍然可用
  • Production App 使用独立凭据
  • Gadget Production 部署成功
  • 生产环境可以安装和测试

结语

Extension-only App 的核心思想是:

Shopify CLI 管理 Extension
Gadget 管理后端和应用连接
Shopify Dev Dashboard 管理应用身份和版本

整个开发链路如下:

创建 Extension-only App
        ↓
生成 Admin Block
        ↓
连接 Gadget
        ↓
配置 API Scope
        ↓
配置 App URL 和 OAuth 回调
        ↓
安装到 Development Store
        ↓
测试 Admin Extension
        ↓
开发 Gadget 后端和前端
        ↓
配置 Access Control
        ↓
使用 Shopify CLI 发布 Extension
        ↓
部署 Gadget Production
        ↓
安装生产应用

如果应用只需要在 Shopify Admin 的指定位置增加一个功能,Extension-only App 可以减少很多无关的前端和部署工作。

如果应用还需要复杂的设置中心、数据管理页面、报表和商家配置,则可以让 Gadget 提供 Embedded App,再将 Shopify Extension 作为应用的一部分。这样既能使用 Gadget 的后端和数据库,也能将功能自然地嵌入 Shopify Admin。