Shopify

Shopify App 技术选型:何时用官方模板,何时混合或自建

从商家的工作位置、分发方式和 Shopify 协议边界出发,对比官方 React Router 模板、混合架构、自建嵌入式 App、API-only 与 extension-only,并梳理授权、Webhook、数据库、计费和审核的生产要求。

约五千八百字·读约十七分钟 · English

Shopify App 技术选型:何时用官方模板,何时混合或自建

对一个新建、面向多商家、需要在 Shopify Admin 中完成核心操作的公开 App,先从 Shopify 官方 React Router 模板起步。只有在产品形态、企业平台约束或 Shopify 托管扩展运行时已经给出明确答案时,才偏离这条默认路线。

官方模板的价值在于,它已经把 App Home、嵌入式认证、Admin API 调用、应用配置和常见 Webhook 入口接成完整的脚手架,让团队更早开始实现业务逻辑。

完全自建也可行,但团队需要自行理解并维护 Shopify 安装流程、OAuth、令牌生命周期和 Webhook 等集成细节。选型时,应把这些长期成本和框架偏好一起评估。

先别急着选模板

很多团队一开始只问:“要不要用 Shopify 模板?” 这个问题问得太早。模板只是实现方式的一部分;在选它之前,先把下面四个问题想清楚。它们会共同决定技术路线,但不能互相替代。

  • 产品形态:商家是否要在 Shopify Admin 内完成日常工作。

  • 分发方式:应用是 public distribution,还是面向单一商店或同一 Plus organization 的 custom distribution。分发方式选定后不能更改。

  • Shopify 边界由谁维护:官方模板、一个保留模板边界的适配层,还是团队自己的实现。

  • 运行位置:应用是开发者托管的 iframe App Home,还是 Shopify 托管的 App Home UI extension。

下面会按这个顺序判断:先看商家在哪里工作,再看能否使用 Shopify 托管的扩展,最后才决定用模板、混合架构还是完全自建。

按顺序做决定

图 1. Shopify App 技术路径选择流程

图 1. 先判断商家工作位置,再判断分发与托管边界。图中的“模板外壳 + 既有服务”适合已有企业平台,但仍希望保留 Shopify 官方接入边界的团队。

第一步:商家是否需要在 Shopify Admin 内完成关键工作

如果商家要在 Admin 中配置规则、查看同步状态、管理订阅、选择商品、处理异常或查看报表,就需要 App Home。对大多数应用,App Home 是开发者托管的 iframe 页面,并通过 App Bridge 与 Shopify Admin 协作。

如果 Shopify 只是 ERP、PIM、WMS、BI 或数据同步服务连接的一个渠道,用户主要在公司自己的系统里工作,独立 Web App 或 API-only 集成通常更自然。面向外部商店时,这类应用仍要走 authorization code grant;只有服务端应用和目标店铺同属同一 Dev Dashboard organization 时,才考虑 client credentials grant。

这里有一个不能省略的边界:普通 public App Store 应用不能以纯站外控制台或纯 API 服务替代商家界面。 App Store 要求商家可操作的 UI,并要求将站外功能直接整合为 Shopify Admin 内一致的嵌入式体验。

第二步:能否完全落在 Shopify 托管的 extension-only 运行时

App Home UI extension 是一条专用路线,不是完整 Web App 的通用简化版。它只适合 custom distribution、无需服务端逻辑、能在 Preact 运行时中完成的轻量页面。它的压缩 bundle 上限为 64 KB,浏览器 API 与 Shopify target API 都是受限子集。超过这些边界后,需要重新实现为 iframe App Home,不能反向迁移。

因此,若需要公开分发、后台任务、Webhook、复杂多页界面、自有持久化或完整 Web 平台能力,应直接选择开发者托管的 App Home。

第三步:谁来维护 Shopify 边界

若需要开发者托管的嵌入式 App,再问下面的问题。

  • 没有必须复用的企业运行时、身份或合规平台时,选择官方 React Router 模板。

  • 既有服务已经承载领域逻辑,但团队仍能保留官方模板或薄 App Home 负责认证、安装和 Webhook 边界时,选择混合架构。

  • 只有既有规范确实不能容纳这一层,且团队愿意长期维护嵌入式认证、令牌、Webhook、配置和升级时,才选择完全自建嵌入式 App。

这个顺序很重要。第一步决定是否需要 App Home,第二步决定是否可用 Shopify 托管运行时,第三步才决定模板、混合还是自建。它们不是同一层级的“例外清单”。

模板、CLI 与 Dev Dashboard 各自解决什么

React Router 模板不是一个封闭平台。它是团队拥有的代码和配置。数据库、队列、监控、缓存、领域模型、内部服务与部署方式都可以替换。真正不应轻易重写的是 Shopify 边界:认证、安装、会话或令牌、Webhook 验证和应用配置。

也不要把 Shopify CLI 的能力误算成模板专属能力。应用注册、Dev Dashboard、shopify.app.toml、本地开发隧道和扩展发布属于 CLI 与平台能力。自建应用同样可以使用它们。模板提供的额外价值,是把这些平台能力与 App Home 路由、服务端认证、会话存储、Admin API client 和 Webhook 路由预先接好。

图 2. Shopify CLI 的官方脚手架体验

图 2. shopify app init 与官方模板的嵌入式 App Home 示例。选择模板不等于放弃 CLI 以外的技术栈;它意味着先采用一套已经接好 Shopify 边界的运行时代码。

先用一张表确定候选路线

路线适合的产品或团队Shopify 边界由谁维护主要投入
A:官方模板 + 模块化单体从零开发、面向多商家的公开 App官方模板与应用团队业务规则、数据、异步任务与生产运维
B:模板边界 + 既有服务已有企业后端,商家仍在 Admin 中工作模板或薄 App Home,连接既有领域服务租户上下文传递、服务权限与任务可靠性
C:完全自建嵌入式 App企业规范无法容纳模板边界层应用团队自行实现并持续维护认证、令牌、Webhook、配置及升级
D:独立 Web App / API-only内部同步、自动化或外部企业控制台应用团队,按受众选择授权流数据映射、限流、失败恢复与对账
extension-only特定客户、custom distribution,功能落在扩展运行时Shopify 托管扩展,团队遵守 target 能力限制扩展功能、运行时和 bundle 限制

路线 D 不能直接作为普通 public App Store 产品的最终形态。 若要公开上架,应补齐商家可操作的 UI 和一致的嵌入式体验。

四条开发者托管路径,加一条专用扩展路径

路径 A:官方模板起步的模块化单体

适合:从零做公开 SaaS App,团队接受 Node 与 React Router,第一版功能主要在 Admin 中,预计有安装、配置、Webhook、后台任务和付费。

模板负责 App Home、常见认证流程和 Shopify API 接入。业务规则放在独立 service 层,不要散在 loader、action 或 UI 组件中。数据库保存安装状态、租户数据和任务状态。Webhook 接收端只做校验、耐久记录与快速确认,worker 再执行同步、导入、通知和重算。

这条路的优势不是“单体”本身,而是团队能先用较少基础设施跑通商家的完整路径。等真实用量和组织边界出现,再拆服务通常更稳。

确定使用模板后,可以接着阅读Shopify 应用开发环境搭建与配置实战教程,了解开发店、CLI 初始化和本地调试的操作流程。那篇教程记录的是旧版 CLI 与 Remix 模板,本文则用于判断 React Router 模板、混合架构和自建路线。

路径 B:模板边界加既有服务

适合:已有 Python、Java、Go、PHP 或 .NET 领域服务,商家仍要在 Shopify Admin 内工作,并且团队能够保留一个 Shopify 专用边界层。

这里的边界层最好继续由官方模板或薄 App Home 承担。它处理安装、嵌入式认证、最少量的会话状态、Shopify API 适配和 Webhook 入口。既有服务继续处理库存、订单、规则、AI、数据仓库和企业权限。

图 3. 模板边界加既有服务的参考架构

图 3. App Home/BFF 负责 Shopify 身份与平台调用,领域服务负责业务数据和规则。Webhook 经过接收层与队列后由 worker 处理,不与浏览器请求共用长事务。

这条路径的关键是租户边界。下游服务不能因为请求来自“Shopify UI”就信任 shop 参数。Shopify 边界层应传递已验证的 shop、安装和用户上下文,下游仍要检查这些信息是否属于当前组织。

路径 C:完全自建嵌入式 App

适合:团队有强制技术标准,且这些标准无法保留官方模板或薄 App Home 作为 Shopify 边界。仅仅因为团队更熟 Next.js、Django 或其他框架,不足以构成理由。

自建团队要先确定实际采用的授权模式,而不是把所有授权流堆到一张图里。

  • 嵌入式请求中,前端从 App Bridge 取得 ID token。后端必须验证签名、exp、nbf、aud、iss 和 dest 等声明,再按需要执行 token exchange。

  • Webhook、队列和定时任务没有浏览器上下文,应使用安全存储的 offline access token。public App 调用 GraphQL Admin API 时应使用 expiring offline token,并安全轮换 access token 与 refresh token。现有 public App 必须在 2027 年 1 月 1 日前迁移,届时 non-expiring offline token 将不能用于 GraphQL Admin API 请求。

  • 若需要按员工权限执行操作,使用 online token;它过期或员工登出后,应在活跃会话中重新取得,而不是当作后台任务令牌。

关于页面请求、员工权限和后台任务分别该用哪种凭证,以及如何保存和刷新可过期 token,可以进一步阅读Shopify Online Token 和 Offline Token 怎么选。

自建的成本不是第一次接上 OAuth,而是以后持续维护这些协议。团队需要明确 owner、自动化测试、升级节奏和线上故障处理。缺少其中任何一项时,路线 A 或 B 更稳。

路径 D:独立 Web App 或 API-only 集成

适合:内部 ERP、WMS、PIM、OMS、数据平台、BI 或自动化服务。商家不需要在 Shopify Admin 内完成主要工作。

面向外部商店时,独立应用走 authorization code grant,需要保存并校验 state、回调 HMAC 与 shop 域名,再按店安全保存 token。 只操作自有组织店铺的服务器端集成可使用 client credentials grant,并按同一 grant 重新取得到期 token。

API-only 不代表“只有几段脚本”。它仍需要按店限流、Webhook 幂等、数据回补、令牌生命周期、失败告警和卸载后的数据处理。若未来目标改为普通 public App Store 产品,就不能维持纯 API-only 形态,必须补上嵌入式 App Home、安装路径和审核材料。

专用路径:extension-only

当功能完全落在 Checkout、POS、Flow、Customer Accounts 或 App Home 的扩展点内,并且只为特定客户以 custom distribution 交付时,extension-only 可以省去自托管 Web 后端。

不要把“需要外部 API”一概等同于必须有后端。某些扩展具备经过声明或批准的网络能力。是否可行必须按具体扩展的 target 和能力核验。反过来,公开分发、后台任务、自有持久化或超出运行时限制的复杂运营界面,仍需要开发者托管的应用。

无论选哪条路线,都要自己负责的生产基线

模板降低的是 Shopify 边界的起步成本,不会替团队拥有生产能力。下面这些要求适用于所有有服务端的生产 App;自建只是在此基础上还要维护 Shopify 协议层本身。

配置与发布

shopify.app.toml 保存应用级配置,例如应用 URL、redirect URL、scope、Webhook 和 app proxy。每个扩展的 type 与专属设置位于其目录的 shopify.extension.toml。这些文件应进入版本控制,开发与生产使用不同配置。

shopify app deploy 发布应用配置和扩展的 app version,不发布 Web 服务。Web 服务仍由 Cloud Run、Render、Fly.io 或其他托管平台单独部署。发布与回退时,要确认 Web 服务版本与 application URL、redirect URL、scope、Webhook 配置彼此兼容。

令牌与权限

服务端保存 token,按店铺隔离,并把 secret、access token 和 refresh token 排除在浏览器、日志与错误追踪之外。Shopify 建议对静态 session 与 access token 加密;本文将其视为生产安全基线,应通过平台 KMS 或受控应用层密钥实现。

每个 scope 都应在 PR 中说明用途、读取或写入的资源、调用时机和移除影响。使用 Shopify managed installation 时,required scopes 来自已部署 TOML 的 [access_scopes].scopes。可选能力应声明为 optional_scopes 后按需请求;写进配置不代表商家已经同意。

Webhook:先可靠保存任务,再告诉 Shopify 已收到

Webhook 是 Shopify 发来的变更通知,不是按顺序、只发送一次的数据库同步。Shopify 可能重复发送,也可能先收到较新的通知,再收到较旧的通知。X-Shopify-Webhook-Id 用于识别同一次投递的重试;同一商家动作触发多个订阅时,每次投递的 ID 不同,但会共享 X-Shopify-Event-Id。

对 HTTPS delivery,接收端应验证原始请求体的 HMAC。随后以 delivery ID 为唯一键,在同一持久化事务中写入接收记录和待执行任务,或写入 transactional outbox。提交成功后,才在 Shopify 的 1 秒连接时限和 5 秒请求时限内返回 2xx。3xx 与其他非 2xx 都会被视为失败。Google Cloud Pub/Sub 和 Amazon EventBridge 使用各自的认证方式,不走这个 HMAC 验证。

worker 再执行第三方调用、批量写入和耗时计算。对“最终状态”为准的新增或更新 topic,可以回读资源并用 updated_at 等版本信息处理乱序;删除、撤销或需要保留状态转换语义的 topic,应保留已验证的 payload 和 headers,不能一律回读当前资源。无论采用哪种方式,都要定期用 API reconciliation 发现并回补漏事件。

图 4. 可靠 Webhook 处理时序

图 4. 可靠处理的关键不是“把任务扔进队列”,而是 delivery 记录和可恢复任务在确认 Shopify 前已经耐久提交。worker 负责后续重试、业务幂等和对账。

数据库与部署拓扑

官方模板默认使用 Prisma 与 SQLite。单一 Web 实例、持久文件系统、已验证的备份恢复、可接受单副本故障窗口时,SQLite 可以用于生产。

持久卷只解决文件不会在重启后消失,不会自动解决多副本并发访问、文件锁或故障切换。若有多个 Web 容器、跨节点扩缩容、高可用需求,或 session、任务和业务数据必须在所有实例之间一致可见,优先选择 PostgreSQL、MySQL 等服务型共享数据库。继续使用 SQLite 时,应由单一数据库实例管理,并验证锁、备份、恢复和滚动发布行为。

API、队列与大任务

新建 public App 自 2025 年 4 月 1 日起必须只使用 GraphQL Admin API。REST Admin API 已是 legacy;本文提到的 REST 429 与 Retry-After 仅适用于存量或不受该 public App 要求约束的集成。

GraphQL 按查询成本限流。每个 shop 应有自己的调度队列,前台请求和 worker 共用该预算,避免一个大客户的全量同步挤掉其他商店。常规节流可能以 HTTP 200 的响应体中的 THROTTLED 出现,客户端应读取 extensions.cost.throttleStatus 后再安排重试。输入数组最多 250 项,常规分页最多 25,000 个对象。

历史导入和批量同步应使用游标、检查点和可重入任务。用户点击“同步”后,应看到可追踪的任务,而不是等待一个浏览器请求直到超时。

分发、计费、隐私与审核

public distribution 允许任意商家从 App Store 安装,需要审核,并可使用 Shopify 的计费能力。custom distribution 面向单一商店或同一 Plus organization,不经审核,不能使用 Billing API。

新公开 App 在定价模型受支持时默认使用 Shopify App Pricing;一次性购买或不受支持的模型需要使用 Billing API 的 Manual Pricing。应用后端仍要拥有自己的 entitlement 判断,让 UI、worker 和内部 API 对当前计划使用同一规则。商家降级后,后台任务也不应继续执行高级功能。

图 5. Shopify App Pricing 的商家订阅流程

图 5. Shopify 承载套餐确认与账单,但应用仍要在服务端根据当前 entitlement 执行功能限制。

App Store 分发的应用必须实现 customers/data_request、customers/redact 和 shop/redact 三个 mandatory compliance webhook。它们不是同一种请求:data request 用于定位并提供数据,redact 请求用于删除或脱敏。有效请求先返回 2xx,并在收到后 30 天内完成相应动作;customers/redact 仅在法律要求保留数据时可以不删除。无效 Shopify HMAC 的 mandatory compliance webhook 必须返回 401。

数据处理范围不只包括主库。缓存、搜索索引、对象存储、队列 payload、数据仓库、分析导出与备份恢复策略都要写明 owner、保留理由和处理方式。

按真实场景给出建议

新建公开 SaaS App

从路径 A 开始。先用模板跑通安装、scope、App Home、卸载、Webhook 和计费,再按真实吞吐和领域边界拆出 worker 或独立服务。不要因为以后可能用微服务,就在第一周先拆出一组没有流量和边界依据的服务。

已有企业后端,商家仍需在 Admin 工作

从路径 B 开始。让 App Home 成为 Shopify 适配层,既有系统继续负责组织、资源、权限、审计和异步计算。先问“能否保留模板边界”,而不是只问“现有后端是什么语言”。能保留就选混合架构;不能保留,才按路径 C 的长期维护成本评估。

内部同步、自动化或后台集成

从路径 D 开始。优先投入数据映射、授权、每店限流、Webhook 可靠性、失败恢复与对账。若只服务同一 Dev Dashboard organization 中的店铺,评估 client credentials grant;若服务外部商店,仍需正确实现 authorization code grant。

Checkout、POS、Flow 或账户侧的单点能力

先核验扩展或 Shopify Function 能否直接覆盖需求。若功能完全落在扩展运行时且只服务特定客户,extension-only 通常成本最低。不要为了一个固定扩展点的能力,自动增加完整 Web 后端。

上线前,验证结果而不是只看页面

下面这些验收项适用于选定路线后的生产应用。每一项都应有测试记录、负责人和失败后的处理方式。

  • 安装与认证:首次安装和卸载后重装时,公开 App 先完成对应的安装与授权流程,再进入试用、计费或业务设置;嵌入式应用应按 managed installation 与 token exchange 的实际流程验收。拒绝 required scope 时不创建可用安装状态;新增 scope 后,只有授权成功才启用依赖该权限的功能。

  • Webhook 与数据任务:同一 delivery 回放两次不会产生第二份业务副作用。新事件先到、旧事件后到时,旧 payload 不会覆盖新状态。失败任务经过有限重试后进入死信队列,能从检查点恢复。

  • 限流与容量:人为注入 GraphQL THROTTLED、worker 重启和并发批任务;仍使用 REST 的存量集成还应测试 429 与 Retry-After。验收标准是任务不丢失,热点商店不阻塞其他商店,且用户请求不依赖浏览器长连接。

  • 安全与租户隔离:篡改或缺失 HMAC 的 HTTPS delivery 不入队、不写库。商店 A 访问商店 B 的资源被拒绝且无数据泄露。日志、错误追踪与支持工具不出现 token、secret 或完整敏感 payload。

  • 配置与回退:分别演练 Web 服务回滚与 Shopify 配置发布/回退。每一步都验证 application URL、OAuth 回调和 Webhook 是否仍与当前代码兼容。

  • 隐私与审核:三类合规 Webhook 都有有效与无效签名测试。审核人员拥有可用账号、完整步骤、有效第三方凭据,以及逐步展示核心功能与预期结果的英文或带英文字幕的视频。

如何做出最终选择

把选型压缩成一句话:先按商家的工作位置选择产品形态,再按分发方式确定审核和计费边界,最后决定谁维护 Shopify 协议层。

需要 Admin 内核心工作、面向公开商家、没有不可绕开的企业平台约束时,用官方模板起步。已有平台但能保留 Shopify 边界时,用模板边界加既有服务。商家不在 Admin 中工作时,选独立或 API-only,并按实际受众选择授权流。需求完全落在扩展运行时且只做 custom distribution 时,再选 extension-only。

模板不是生产架构的替代品。它只是让团队更早把注意力放到商家真正会感受到的结果上:安装是否顺利,数据是否正确,出错时是否能恢复并说清原因。

参考资料

平台规则核对日期:2026 年 10 月 4 日。

Mttao

Mttao GitHub ↗

探索技术与生活的智慧

相关文章

/ 评论