Shopify 主题开发的交付物不是一堆能在浏览器里出现的文件,而是一条可以解释、检查、恢复的界面链路。它从需求分类开始,经过目录契约、Liquid 数据边界、JSON 模板、section 与 block、应用扩展、开发主题、代码评审和上线验收,最后留下可追溯的版本与回退证据。本文把每个边界都写成可以由设计、开发、内容、商家和值班人员共同执行的检查项;预算是团队的验收门槛,不是平台能力或业务结果的承诺。
1. 先把需求归类为正确的层
1.1 用用户可见结果描述需求
先写“用户在什么页面看到什么状态”,再决定实现层。商品卡片的价格显示、集合页的排序入口、购物车的空状态通常是主题呈现;跨页面持久化的业务规则、敏感数据读取、异步同步和结账限制则需要更合适的应用或后端边界。把所有问题都塞进 Liquid,会让模板承担不可测试的职责,也会让一次视觉改动触发无法解释的业务变化。
一个可执行的需求单至少包含页面类型、数据来源、可交互动作、无脚本结果、语言与市场条件、验收证据和回退动作。不要只写“做一个更灵活的组件”。要写清楚商家在主题编辑器中能配置哪些字段、访客没有 JavaScript 时看到什么、字段为空时怎样降级,以及哪一种数据变更不应该由主题代码负责。
| 需求信号 | 首选层 | 主题应交付的可见结果 | 不应放入主题的部分 |
|---|---|---|---|
| 只改变版式、文案或展示顺序 | 主题 section、block、snippet | 可配置区域、稳定的空状态、响应式 HTML | 订单状态写入、跨系统同步 |
| 需要读取 Shopify 商品或集合对象 | Liquid 与模板上下文 | 按对象字段渲染的页面和明确的缺省值 | 在文件中硬编码库存或价格 |
| 需要商家在编辑器中组合模块 | JSON 模板、schema、section | 可添加、删除、排序的模块与设置说明 | 把编辑器设置当作权限系统 |
| 需要注入应用界面或应用设置 | Theme App Extension | 可定位的 app block、设置和卸载后的空位 | 复制应用内部文件到主题 |
| 需要修改结账规则或计算业务结果 | 应用、Function 或服务层 | 主题只呈现已确认的结果 | 在 Liquid 中伪造价格、折扣或资格 |
| 需要跨系统重试、审计或敏感权限 | 后端集成与独立凭据 | 主题展示安全的结果或错误说明 | 在前端暴露令牌、重试队列或私密数据 |
1.2 写一张边界决策单
边界决策单要有 owner 和反例。比如“显示会员标签”如果只是读取已经安全暴露的标签,可以属于呈现;如果标签需要实时查询客户隐私数据,就必须先验证权限、缓存和删除路径。每个需求只允许一个主实现层,其他层写成输入或输出,不要让主题和应用同时拥有同一份真相。
建议在评审时逐行回答四个问题:这个字段是谁拥有?它什么时候更新?空值和错误怎样显示?出现不一致时谁有权修复?如果答案依赖一个未定义的全局变量,需求还没有达到可开发状态。将决策单和验收样例放在同一个版本目录,后续升级时才能判断是代码变化还是业务前提变化。
2. 建立可读的主题仓库契约
2.1 目录职责要固定
主题仓库的目录名本身就是协作接口。layout 负责页面外壳和全局输出,templates 负责页面类型的组合,sections 负责可以被模板或编辑器放置的模块,snippets 负责可复用但不独立布局的片段,assets 负责 CSS、JavaScript 和媒体引用,config 负责主题设置与默认值。职责清楚时,评审者可以从文件位置推断影响面;职责混乱时,任何小改动都要依靠运行时猜测。
不要用一个巨大的 section 代表整个首页,也不要把所有逻辑塞入一个 snippet。文件应围绕一个用户任务或一个显示契约组织。一个 section 可以组合多个 block,但每个 block 都要有单一的设置结构和明确的空状态。模板只负责组合,不应悄悄修改对象或承担应用同步。
| 目录或对象 | 适合承载 | 评审证据 | 常见越界 |
|---|---|---|---|
layout | HTML 外壳、全局 head、全局资源入口 | 页面源代码和资源清单 | 把单页业务查询放到全局 |
templates | 页面类型与 section 顺序 | JSON 结构、页面路由样例 | 在模板中复制一套组件逻辑 |
sections | 可配置模块和 block 容器 | schema、空值和移动端样例 | 依赖不可见的全局状态 |
snippets | 小型、可复用的输出片段 | 输入字段、输出 HTML、调用清单 | 在片段里藏副作用 |
assets | 页面所需样式与脚本 | 加载条件、错误回退、体积记录 | 每页无条件加载全部脚本 |
config | 设置定义与默认配置 | 设置类型、默认值、迁移说明 | 把秘密、令牌或订单事实写入设置 |
locales | 各语言的界面文案与回退键 | 语言键、缺失键、长文案样例 | 把文案硬编码在模板或图片 |
| 应用扩展目录 | 应用拥有的扩展资源 | 扩展配置、安装和卸载验证 | 把扩展文件当普通主题文件编辑 |
2.2 让命名成为可搜索的接口
命名应说明页面角色和动作,例如 product-card、cart-line 或 media-gallery,不要用 new-final-v2 这类无法解释的名字。变量名要表达是对象、设置、派生显示值还是状态。循环内部只保留当前循环需要的短变量,并在跨 snippet 传值时写出输入契约。
locales 目录也要像代码一样接受评审:键名表达用途,回退语言明确,长文案和缺失键有 fixture。仓库还需要一份简短的 README,说明本地预览的入口、主题设置的来源、检查命令的版本、哪些目录由应用拥有、哪些改动需要设计或内容评审。README 不是替代代码注释,而是让新成员能在不接触真实店铺数据的情况下复现一个页面。
3. Liquid:呈现、过滤与数据边界
3.1 先确认对象再读字段
Liquid 负责组合已经在页面上下文中可用的 Shopify 对象。开发时先确认对象类型、字段是否可能为空、字段是否会因市场或模板不同而缺失,再写输出。不要把商品标题当作稳定 ID,不要用标题拼接 URL,不要把当前语言或国家写死在条件分支中。显示价格时要保留平台已经提供的货币语境,不要用字符串替换模拟换算。
一个健壮的片段会把“没有对象”“对象没有字段”“字段为空字符串”视为不同情况,并为每一种情况准备可读的降级。比如商品卡片没有图片时仍然保留标题、价格和可操作链接;推荐模块没有推荐结果时收起模块,而不是输出一个空容器。这样做也便于无脚本验收,因为核心导航和主要信息不依赖一次异步请求。
| 数据问题 | Liquid 层的安全动作 | 用户看到的回退 | 应记录的证据 |
|---|---|---|---|
| 对象根本不存在 | 先做存在性判断 | 隐藏依赖对象的模块并保留页面结构 | 路由、模板、测试数据 |
| 字段未提供 | 使用显式缺省文案或省略字段 | 说明信息暂不可用,不伪造值 | 字段清单和截图 |
| 列表为空 | 输出空状态或不渲染容器 | 给出下一步导航,不留空白卡片 | 空列表 fixture |
| 市场或语言不同 | 读取上下文或设置的结果 | 保留本地化格式与方向 | 市场、语言、方向组合 |
| 业务值需要计算 | 只显示已确认的输入结果 | 说明等待确认或引导到合适流程 | 计算 owner 与来源 |
3.2 控制循环、过滤器与副作用
先把需要的字段列成小集合,再写循环。无界的嵌套循环、反复执行同一个过滤器、在多个 snippet 重复计算,会让模板的渲染成本难以解释。把排序、分页和主键选择交给支持这些能力的上游对象或服务;主题只做展示所需的轻量转换。
Liquid 输出不应发起不可见的写操作,也不应承担重试。JavaScript 需要交互时,先让 HTML 提供可用的初始状态,再用脚本增强。脚本失败、被拦截或加载延迟时,用户仍应能浏览、选择和获得错误说明。此边界同时降低应用脚本冲突时的影响面。
4. JSON 模板、section、block 与 schema
4.1 把编辑器设置当成类型契约
schema 是商家可以理解的设置表,不是随意暴露的变量列表。每个 setting 都要有标签、默认值、允许的范围或选项、空值行为和一个实际页面样例。block 的设置应只描述该 block 的内容和显示行为;section 的设置才描述整个容器的布局。设置名称、默认值和数据类型一旦被使用,就应当当作兼容接口维护。
JSON 模板负责声明页面由哪些 section 组成以及每个 section 的配置。开发时用最小模板验证一件事,再组合复杂页面。一个页面同时放置多个依赖同一资源的 section 时,要确认资源是否重复加载;一个 section 被删除时,要确认核心导航、标题和表单仍然有可用路径。
| 设计项 | 可接受契约 | 验收问题 | 失败回退 |
|---|---|---|---|
| setting 类型 | 与输入目的匹配,默认值可渲染 | 空值、极端长度、特殊字符是否安全 | 隐藏可选装饰并保留文本 |
| block 数量 | 有合理上限或清晰的重排行为 | 首尾、单个、很多个 block 是否一致 | 使用简化布局 |
| section 顺序 | 由 JSON 模板明确声明 | 移动一个 section 是否破坏标题层级 | 回到最小模板 |
| 可选媒体 | 有宽高、替代文本和缺失状态 | 图片慢或失败时是否仍有信息 | 文本和占位结构 |
| 动态字段 | 来源和缺省值可追溯 | 字段不存在时是否误显示 | 省略字段并保留操作 |
| 设置迁移 | 改名或删除有说明 | 旧配置打开时是否报错 | 使用兼容默认值 |
4.2 处理 section 与 block 的组合边界
section 是布局容器,block 是可以移动的内容单元。不要让 block 直接假设另一个 section 一定存在;不要用 DOM 查询去猜兄弟 section 的顺序。需要共享信息时,使用稳定的设置、上下文对象或明确的服务输出,并为缺失情况写独立测试。
开发者还要测试编辑器预览与真实店铺页面的差别。编辑器可能显示选中边框、占位内容或未保存设置,而真实页面只应显示已保存配置。验收记录要注明是在编辑器、预览还是公开主题中完成的,避免把编辑器的临时状态当成访客可见结果。
5. 应用扩展与主题文件的清晰边界
5.1 用 app block 表达可卸载的界面
当界面由应用提供时,优先使用 Theme App Extension 的 app block 或扩展配置,让应用拥有自己的资源和生命周期。主题只负责允许放置、传递必要设置和保持布局空间。应用卸载、禁用或请求失败后,主题应能隐藏空 block,并保留周边内容可用;不能复制一份应用代码进主题,再假设卸载会自动清理。
应用扩展的设置要标明谁可以修改、哪些字段会被保存、无权限时显示什么。需要全局入口时使用 app embed block;它的启用、停用和资源范围应与页面级 app block 分开验收。不要把应用的令牌、内部接口或重试队列写进主题设置。应用需要服务器数据时,主题最多消费经过授权的渲染结果,并为超时、空结果和版本不匹配准备文案。
| 场景 | 主题负责 | 应用扩展负责 | 验收与退出证据 |
|---|---|---|---|
| 放置一个推荐模块 | 提供 app block 的布局位置 | 获取推荐并渲染扩展内容 | 空结果不挤压主内容 |
| 加载扩展资源 | 只在需要的页面保留入口 | 管理扩展资源与初始化 | 资源清单和卸载后页面 |
| 保存商家设置 | 提供可理解的容器设置 | 维护扩展自己的配置契约 | 旧设置、空设置样例 |
| 请求失败 | 保留标题、导航和主要操作 | 告警、诊断和重试策略 | 失败屏幕与恢复步骤 |
| 应用移除 | 隐藏空 block,不复制文件 | 清理自己的扩展状态 | 移除后无残留脚本和样式 |
| 全局 app embed | 保留页面语义和关闭后的基础体验 | 管理全局入口、配置和资源 | 停用后核心页面无脚本错误 |
5.2 诊断应用与主题的冲突
冲突诊断要先建立最小复现:相同商品、相同市场、相同主题副本,只切换一个应用或一个 block。记录页面路径、模板、资源顺序、控制台错误、DOM 变化和时间点。若关闭应用后问题消失,不等于主题没有问题;还要判断主题是否依赖了应用注入的全局变量或样式。
处理顺序应是隔离、取证、降级、修复、回归。先禁用有争议的 block 或资源,再确认核心页面可用;不要同时升级主题、应用和浏览器脚本。对样式冲突,优先收窄选择器和加载范围;对脚本冲突,优先避免重复初始化和未检查的全局命名;对数据冲突,回到唯一来源并暂缓显示不确定结果。
6. CLI 与开发主题的安全工作流
6.1 开发主题先于真实主题
每个任务从独立的开发主题开始。开发主题用于短期实验和实时预览,通常是临时且隐藏的;它不等同于可以长期保留的未发布主题,也不是用来承载长期业务数据的第二业务系统。需要可持续评审时,把已通过检查的版本放到未发布主题,明确它与临时开发主题的访问边界。开始工作前,记录主题名称、基线版本、负责人和访问范围;结束时保存预览地址、检查输出和差异摘要。
Shopify CLI 的使用要以当前官方文档和团队安装版本为准,使用明确的主题开发、检查、推送和发布动作,不在脚本中埋入未经核对的参数。开发主题的实时预览、未发布主题的持久评审和发布到当前主题是三个不同动作;推送不应被当作发布的同义词。命令执行前先确认目标主题,执行后保存终端结果。任何会覆盖或改变共享主题的动作都要先经过评审和回退准备。
| 工作阶段 | CLI 或平台动作 | 必留证据 | 停止条件 |
|---|---|---|---|
| 创建隔离空间 | 连接并选择开发主题 | 主题标识、操作者、开始时间 | 目标不明确或权限过宽 |
| 本地迭代 | 启动主题预览并改动小范围文件 | 预览地址、页面路径、差异 | 预览无法稳定复现 |
| 静态检查 | 运行 Theme Check | 输出、版本、错误位置 | 有未解释的错误或警告 |
| 预览验收 | 在代表性设备与语言中检查 | 截图、键盘路径、控制台 | 核心操作或无脚本状态失败 |
| 共享评审 | 推送到未发布的评审主题 | 变更摘要、审阅意见 | 没有回退版本或 owner |
| 上线动作 | 将已批准的未发布主题发布 | 版本名、时间、结果 | 发现未审计差异或目标混淆 |
6.2 预览数据要能被重复使用
开发主题的 fixture 不应依赖某个成员的个人草稿。准备至少一个有媒体和变体的商品、一个空集合、一个多语言页面、一个应用 block 失败样例和一个没有 JavaScript 的路径。fixture 只用于复现界面,不应包含真实客户信息、访问令牌或无法公开的订单细节。
预览时按页面类型而不是按文件逐个点击。首页、集合、商品、搜索、购物车、内容页和错误状态分别记录路径。发现问题后保留最小复现步骤,再修正一个变量。这样后续评审能够判断修复是否改变了原来的失败模型。
7. 预览与验收矩阵
7.1 覆盖页面、状态和方向
验收不是“首页看起来正常”。矩阵至少覆盖页面类型、数据状态、语言方向、设备输入和应用开关。把最容易失败的组合放在前面:缺图商品、空集合、长标题、右到左语言、窄屏键盘、脚本被阻断,以及应用返回空结果。每一项都要有预期、实际、证据和回退动作。
| 维度 | 代表值 | 观察点 | 通过证据 |
|---|---|---|---|
| 页面 | 首页、集合、商品、搜索、购物车、内容 | 模板、标题层级、主要操作 | 路径与截图 |
| 数据 | 正常、空、缺字段、长文本 | 缺省值、截断、换行 | fixture 与结果 |
| 语言 | 中文、英文、右到左语言 | 文案、方向、数字和日期 | 语言设置与截图 |
| 设备 | 窄屏、桌面、触摸、键盘 | 溢出、焦点、触控尺寸 | 设备视口记录 |
| 脚本 | 正常、延迟、失败、禁用 | 核心内容和操作是否仍在 | 无脚本截图与日志 |
| 应用 | 启用、空结果、超时、移除 | block 空间、冲突、残留 | 开关前后差异 |
7.2 定义可重复的验收顺序
先确认 URL 和模板,再确认页面主标题与导航,然后检查内容、表单、媒体和交互,最后检查资源、控制台与错误日志。一次只改变一个变量;如果主题编辑器设置、应用配置和测试商品同时改变,任何结果都无法归因。
验收结果采用“通过、带条件通过、阻断”三种状态。带条件通过必须写明影响页面、owner、截止时间和回退动作,不能用一句“后续优化”替代。阻断项包括错误链接、无法提交的表单、键盘无法完成的核心路径、跨语言混排、敏感信息暴露、主题检查失败和无法解释的资源爆发。
8. Theme Check 与持续检查
8.1 把静态警告变成可处理的工作项
Theme Check 的价值在于把 Liquid、schema、模板和主题约定的风险定位到文件与行。每次检查都保存工具版本和输出,不要只截取绿色摘要。对警告要写明是真问题、已接受的例外还是需要改写的结构;例外必须有 owner 和复查条件。
静态检查不能替代浏览器与真实数据验收。Theme Check 还应重点审阅阻塞脚本、远程资源、缺少图片尺寸、过度分页等性能信号;修复时要定位到资源或 Liquid 结构,而不是简单关闭规则。一个没有语法错误的模板,仍可能在空对象、右到左语言、长文本或应用移除时破坏布局。因此 CI 应把静态检查、渲染 fixture、链接检查和人工矩阵分成相邻但独立的门,失败时能准确知道哪一层需要回退。
| 检查门 | 触发时机 | 检查内容 | 失败处理 |
|---|---|---|---|
| 格式与语法 | 每次提交 | Liquid、JSON、schema 结构 | 修复后重新检查 |
| Theme Check | 每个评审版本 | 规则、弃用风险、文件位置 | 解释或关闭评审 |
| 性能规则 | 每个评审版本 | 阻塞脚本、远程资源、图片尺寸、分页风险 | 缩小资源范围并复测 |
| fixture 渲染 | 主题版本形成时 | 页面状态、空值、错误状态 | 保留上一个可用版本 |
| 浏览器回归 | 共享预览前 | 控制台、键盘、响应式 | 隔离失败页面 |
| 链接与元数据 | 评审完成前 | URL、标题、语言、结构 | 阻止上线动作 |
| 发布后观察 | 上线后短窗口 | 关键页面与错误信号 | 触发回退判断 |
8.2 CI 要避免假绿色
CI 中的 fixture 应固定输入并明确版本,不能依赖当前个人主题、外部网络或临时应用响应。把每个页面的 HTML 结构、链接集合、资源集合和关键文本做可读的差异,而不是只比较整体哈希。差异发生时,评审者要能看到是预期的标题变化,还是意外删除了表单、焦点或替代文本。
当检查工具自身升级时,先在隔离分支运行旧规则与新规则,整理新增警告,再安排代码变更。不要把“升级工具”和“重构主题”塞进同一批不可分割的改动。这样才能在失败时只恢复规则版本或只恢复主题差异。
9. Git、评审与版本证据
9.1 一个提交只表达一个可解释的变更
提交信息要说明页面范围、用户结果、数据依赖和回退方式。视觉间距、Liquid 数据修正、应用 block 接入和资源拆分尽量分开,使评审者能按风险阅读。不要在同一个提交里顺手格式化整个仓库,也不要把自动生成的巨大差异和人工代码混在一起。
评审描述需要列出修改文件、未修改的边界、测试路径、语言和设备组合、已知限制以及恢复上一个版本的动作。截图只证明一个视图,不能替代状态矩阵;命令输出只证明一次运行,不能替代失败回退说明。版本标签或主题版本名称要与评审记录一一对应。
| 评审问题 | 所需证据 | 通过标准 | 否决信号 |
|---|---|---|---|
| 影响了哪些页面 | 文件到模板的映射 | 页面范围可列举 | “全站应该没问题” |
| 改动读取什么数据 | 字段与对象清单 | 来源、空值和 owner 明确 | 硬编码事实 |
| 依赖哪些应用 | app block 与资源清单 | 可关闭、可卸载、可降级 | 复制应用代码 |
| 是否可访问 | 键盘、焦点、标签证据 | 核心路径可完成 | 只看颜色或鼠标 |
| 是否可回退 | 版本、差异和步骤 | 一步一步可执行 | 没有已知好版本 |
| 哪些事实不确定 | 限制与复查日期 | 不确定性被标注 | 把假设写成保证 |
9.2 保护主题设置与内容
代码版本和主题编辑器设置可能分开变化。评审时同时记录代码版本、JSON 模板、设置快照和代表性页面,不能只保存 Git 差异。若商家在编辑器中调整了标题、媒体或 section 顺序,要确认回退代码不会意外覆盖这些设置;若设置结构改变,要给旧设置一个兼容路径。
权限也属于版本证据。主题开发者、评审者、商家和应用 owner 的职责要分开,最小权限足够完成任务即可。离开项目的成员不应继续持有共享主题访问;访问变更应记录,不把个人账号或临时密码写入仓库。
10. 性能预算与可持续渲染
10.1 用页面预算约束资源
性能预算是为了发现资源逐渐膨胀,不是对所有网络、设备或用户作固定保证。预算要按页面类型和资源类型记录,测量条件保持一致,并同时看 LCP 资源优先级、服务端渲染的必要内容、长任务、媒体尺寸和第三方脚本。一次超过预算不代表结论已经确定,但必须说明原因、影响范围和处理动作。
| 页面资源 | 团队验收预算 | 测量方式 | 超出后的动作 |
|---|---|---|---|
| 首屏关键 HTML | 压缩后不超过 170 KB | 记录预览响应与页面路径 | 移除重复片段并复测 |
| 首屏关键 CSS | 不超过 24 KB | 记录关键样式入口 | 拆分非关键样式 |
| 首屏主题 JavaScript | 不超过 120 KB | 记录页面实际加载集合 | 延后非关键交互 |
| 首屏主媒体 | 不超过 220 KB | 记录来源、尺寸和格式 | 更换尺寸或延后加载 |
| 第三方脚本 | 默认不超过 3 个入口 | 记录 owner 与执行时机 | 关闭、延后或合并入口 |
| 字体请求 | 首屏不超过 2 个 | 记录字体用途与回退 | 使用系统字体或减少变体 |
| 页面长任务 | 单项不超过 50 ms | 浏览器性能记录 | 拆分初始化与监听 |
| LCP 主资源 | 仅对真正的首屏主媒体保留优先级 | 页面资源瀑布、fetchpriority 和尺寸 | 移除 lazy loading 或错误优先级 |
10.2 让预算能解释变化
每个资源都要能回答“哪个页面需要它、谁拥有它、关闭后怎么回退”。不要因为某个应用要求就全站加载脚本;让应用 block 只在放置它的页面出现入口,并在初始化前判断元素是否存在。不要用一个大包解决所有页面,也不要把未使用的 polyfill 当作默认依赖。
首屏关键内容应由主题服务端输出,不能等待脚本拼出商品标题、价格、主要导航或表单。真正的 LCP 资源不要默认 lazy loading;只有在它确实是首屏主资源且测量证明需要时,才使用合适的优先级提示。媒体要有明确尺寸、替代文本和加载时机。背景装饰不能阻塞主要内容;商品主图要在布局中预留空间,避免加载后推动按钮。Shopify CDN 和平台传输能力可以帮助交付,但不能替代源文件的尺寸、格式和使用范围检查。出现慢加载时,先定位资源和页面,不用一个总分掩盖长尾页面。
11. 可访问性与国际化验收
11.1 键盘与屏幕阅读器先走核心任务
核心任务包括打开导航、跳到主要内容、选择变体、加入购物车、修改数量、关闭对话框和查看错误。每个任务都要从键盘开始,焦点顺序应符合视觉顺序,焦点样式清晰且不会被 sticky 元素遮挡。按钮、链接、输入框和对话框要有正确的语义和名称,不把点击事件绑在没有交互语义的装饰元素上。
屏幕阅读器验收要听到页面标题、区域名称、表单标签、错误关联和状态变化。动态更新要有适当的通知方式,但不要让每一个装饰变化都打断阅读。隐藏内容必须真的不可达,展开内容打开后焦点位置要可预测,关闭后焦点回到触发点。按钮和主要触控目标至少按 44×44 px 的页面指引检查;颜色对比、非自动播放媒体和可见焦点也要单独记录。图片替代文本描述用途,而不是重复文件名。
| 测试项 | 中文页面样例 | 英文或右到左样例 | 通过证据 |
|---|---|---|---|
| 页面标题与语言 | 标题、lang、中文读法 | English title、language、direction | DOM 与朗读记录 |
| 主导航 | 键盘展开、跳过链接 | Same path with translated labels | 焦点路径 |
| 商品选择 | 变体名称、状态、错误 | Variant names and state changes | 表单录屏与 DOM |
| 购物车操作 | 数量、移除、空状态 | Quantity, remove, empty state | 键盘完成结果 |
| 对话框 | 打开、陷阱、关闭回焦 | Same behavior with longer labels | 焦点前后记录 |
| 图片与图标 | 用途替代文本、装饰隐藏 | Localized purpose text | 属性检查 |
| 动态错误 | 错误与字段关联 | Error text matches locale | 屏幕阅读器输出 |
| 对比与媒体 | 文本对比、无自动播放 | Same checks for long labels | 色彩取样与播放状态 |
| 触控目标 | 主要按钮不互相遮挡 | Target remains usable in RTL | 视口截图与尺寸记录 |
11.2 把翻译和方向当作布局输入
翻译不是把中文字符串替换成英文字符串。英文可能更长,右到左语言会改变箭头、图标和左右间距,数字、日期、货币和产品名称也有自己的格式。所有按钮、标签、错误、空状态和替代文本都要进入语言清单;不要把只在中文页面出现的字串埋在 JavaScript 或图片里。
验收时使用长文案、缺失翻译、混合数字和右到左方向。检查导航是否溢出、价格符号是否贴错位置、图标是否表达相反方向、焦点顺序是否仍合理。缺少翻译时,使用明确的回退语言并记录,不要输出翻译键名。若某个应用 block 不支持当前语言,主题应保留布局和说明,而不是显示空的脚本错误。
12. SEO、结构化信息与语义 HTML
12.1 由模板拥有页面语义
每个页面类型应明确页面标题、描述、canonical、语言关联和唯一的主要标题。主题负责输出正确的语义结构,不应让同一信息由 layout、section 和应用各输出一遍。商品结构化信息只能使用页面上真实可见且来源明确的字段;缺少字段时省略或降级,不要为了通过检查而编造价格、库存、评价或资格。
语义 HTML 也服务于可访问性和维护。导航使用导航元素,主要内容有清晰的区域,按钮执行动作,链接改变位置,表单控件有标签。不要用标题标签只为获得更大的字,也不要跳过层级来实现视觉效果。SEO 验收应与页面状态、语言和应用开关一起完成,因为重复 head、错误语言或残留脚本常常来自组合问题。
| 页面类型 | 必须核对 | 常见误差 | 回退动作 |
|---|---|---|---|
| 首页 | 主要标题、描述、导航区域 | section 重复输出标题 | 保留一个页面主标题 |
| 集合页 | 集合名称、分页、筛选语义 | 空集合仍输出错误链接 | 输出空状态导航 |
| 商品页 | 商品字段、媒体、变体状态 | 把不可见值写入结构化信息 | 省略缺失字段 |
| 搜索页 | 查询状态、结果数、空状态 | 把查询词当页面标题模板 | 显示安全的查询语义 |
| 内容页 | 标题层级、作者区域、链接 | 应用重复 canonical | 由页面模板统一输出 |
12.2 检查多语言 URL 与内部导航
语言路径要和页面语言一致,链接标签也要使用同一种语言。不要在中文页面塞入英文服务入口来填充链接数量,也不要把语言切换链接伪装成普通内容链接。URL、canonical 和 hreflang 的组合必须在每个语言路径中核对;同一个页面的语言版本应互相指向,而不是把所有语言都指向默认页。
在内容中需要进一步阅读时,可以参考Shopify 主题架构与维护运营、Shopify Liquid 主题定制、主题应用扩展治理、Shopify 性能工程和Shopify 多语言本地化。这些页面分别承担运营维护、Liquid 架构、扩展边界、性能诊断和本地化输入,不能替代本文的主题生命周期流程。
13. 发布前清单与职责矩阵
13.1 逐项完成上线清单
上线清单要按先后顺序执行,并让每项都有证据。先确认版本和主题目标,再检查静态输出、模板和 schema,然后执行页面矩阵、键盘与屏幕阅读器、性能预算、语言和应用冲突测试。最后保存批准记录、版本名称和可回退的上一个版本。清单不是口号;缺少证据的项目只能标记为未完成。
| 顺序 | 检查项 | 证据 | 阻断条件 |
|---|---|---|---|
| 1 | 目标主题与版本 | 名称、版本、操作者 | 目标或权限不明确 |
| 2 | 差异与目录边界 | 文件列表、影响页面 | 发现未审计文件 |
| 3 | Liquid 与 schema | Theme Check 输出 | 有未解释错误 |
| 4 | 模板与空状态 | 页面矩阵、fixture | 空对象破坏主路径 |
| 5 | 应用扩展 | 开关、移除和冲突记录 | 有残留或全站脚本 |
| 6 | 可访问性 | 键盘、朗读、错误状态 | 核心路径不可完成 |
| 7 | 性能预算 | 资源和长任务记录 | 预算超出且无处置 |
| 8 | 语言与语义 | 语言路径、标题、标签 | 混语或方向错乱 |
| 9 | 回退准备 | 上一版本和步骤 | 无法快速恢复 |
| 10 | 批准与观察 | 审阅、时间、观察窗口 | 没有明确负责人 |
13.2 用 RACI 让责任可追踪
RACI 不是把所有人都列成“共同负责”。每项工作只设一个 A,R 可以是执行团队,C 是提供输入的角色,I 是需要知道结果的人。对于应用扩展,应用 owner 对自己的配置和失败路径负责;主题 owner 对布局降级、资源范围和语义 HTML 负责。商家批准的是业务结果和内容,不应被迫承担代码诊断。
| 活动 | 主题开发者 | 技术评审者 | 商家或内容 owner | 应用 owner | 值班负责人 |
|---|---|---|---|---|---|
| 需求边界与页面样例 | R | C | A | C | I |
| Liquid、schema 与模板 | R | A | C | I | I |
| 应用 block 配置 | C | C | A | R | I |
| 可访问性与语言矩阵 | R | A | C | C | I |
| 性能预算与资源清单 | R | A | I | C | I |
| 版本批准与上线 | R | C | A | C | I |
| 故障隔离与回退 | C | C | I | R | A |
| 事后记录与修复 | R | A | I | C | C |
14. 版本控制、主题升级与兼容性
14.1 先建立兼容性表
升级主题时,先列出主题代码、JSON 模板、设置键、应用 block、脚本入口、语言资源和人工改动。逐项标记“可以原样带入、需要转换、需要重新验收、应当移除”。不要把新主题的文件直接覆盖旧主题,也不要把旧设置是否能打开当作唯一兼容证明。
| 资产 | 升级前核对 | 升级后的验证 | 不通过的动作 |
|---|---|---|---|
| JSON 模板 | section 名称与顺序 | 页面类型仍有主要路径 | 恢复旧模板并转换 |
| schema 设置 | 键、类型、默认值 | 编辑器打开和保存 | 使用兼容默认值 |
| Liquid snippet | 输入对象与空值 | 正常与缺字段 fixture | 隔离片段并回退 |
| 应用 block | 扩展配置与资源 | 启用、禁用、移除 | 禁用 block,保留布局 |
| CSS 与脚本 | 入口、选择器、初始化 | 控制台和性能预算 | 拆分或延后资源 |
| 语言资源 | 键和回退语言 | 长文案与方向 | 恢复旧翻译路径 |
| 商家内容 | 设置快照与媒体 | 编辑器和公开预览 | 恢复设置快照 |
14.2 把变更记录留在仓库之外的事实也写清楚
主题代码不能代表所有店铺状态。记录应用版本、主题编辑器设置、代表性商品与市场、权限变更和已知例外,评审者才知道一次回退会恢复什么、不会恢复什么。不要声称代码回退可以撤销商家后来手工改变的内容,也不要用时间戳猜测哪个版本更可靠。
升级后再次执行小范围页面测试,再扩大到完整矩阵。若新主题只有一个页面失败,就保留上一个可用版本和最小失败样例;若失败涉及导航、购物车、表单、语言或敏感信息,则停止扩大范围,先回到上一个版本。
15. 失败案例:应用脚本破坏主题导航
15.1 复现与证据
一个跨境店在主题中加入推荐 app block 后,窄屏菜单的关闭按钮失去焦点,键盘用户无法回到触发点;同时应用脚本在所有页面初始化,即使只有商品页放置 block。首页看似正常,商品页的控制台却出现重复初始化提示。问题不是“某个浏览器不兼容”一句话可以解释,需要保留同一主题副本、同一语言、同一商品和应用开关的对照。
复现步骤是:先在没有 block 的开发主题打开导航,再只放入商品页 block;使用键盘打开菜单、触发推荐模块、关闭菜单并重新打开;切换到英文长文案和右到左测试语言;最后关闭应用脚本入口。记录焦点元素、资源顺序、DOM 属性、控制台输出和每一步的页面截图。这样可以区分主题焦点管理、应用初始化和语言布局三个因素。
15.2 回退和修复
先关闭有问题的 app block,确认主导航、购物车和商品选择仍可用,再保留上一个主题版本作为安全参考。主题修复只在菜单组件中恢复焦点回到触发点,并让应用初始化先检查 block 是否存在;资源入口改为按页面加载。应用 owner 处理推荐接口超时和空结果,主题 owner 处理空 block 与键盘降级,值班负责人决定何时恢复 block。
16. 失败案例时间线与恢复边界
16.1 用时间线定位责任
时间线应把观察、动作、证据和决定分开。不要把事后推测写成当时已经知道的事实。每一行只记录一个事件,并注明使用的主题版本和应用开关。恢复后保留失败版本的只读差异,用于修复回归,不把失败版本重新当作默认版本。
| 时间点 | 事件 | 观察到的信号 | 决定与证据 |
|---|---|---|---|
| 09:00 | 建立开发主题 | 页面矩阵通过 | 保存版本与 fixture |
| 09:25 | 加入商品页 app block | 商品页资源增加 | 记录差异与 owner |
| 09:40 | 键盘回归开始 | 关闭后焦点消失 | 标记阻断并截图 |
| 09:55 | 关闭 app block | 导航恢复 | 证明隔离有效,不证明根因 |
| 10:10 | 复查初始化脚本 | 所有页面都有入口 | 准备按页加载修复 |
| 10:35 | 修复焦点与资源条件 | 核心路径通过 | 保存 Theme Check 与矩阵 |
| 11:00 | 复测语言和空结果 | 无残留脚本、焦点稳定 | 应用 owner 复核 |
| 11:25 | 评审可回退版本 | 上一版本仍可用 | 由值班负责人决定恢复范围 |
16.2 回退决策表
回退是恢复可用页面,不是删除证据。先判断失败范围和数据边界,再选择关闭 block、恢复资源、恢复主题版本或暂缓应用。涉及客户隐私、核心导航、购物车、表单提交或语言路径时,阈值应更保守;仅影响非关键装饰时,可以隔离模块并保留版本观察。
| 信号 | 影响范围 | 立即动作 | 继续修复前的条件 |
|---|---|---|---|
| 单一装饰样式错位 | 一个可选 section | 关闭 section 或恢复样式 | 核心路径与焦点通过 |
| 应用 block 空白 | 一个商品模块 | 禁用 block,保留商品信息 | 空状态有说明 |
| 菜单或购物车键盘失败 | 多个核心页面 | 恢复上一可用主题版本 | 键盘路径逐项复测 |
| 语言路径混乱 | 一个或多个市场 | 暂缓语言变更并恢复链接 | canonical 与语言矩阵通过 |
| 敏感字段意外可见 | 任何公开页面 | 立即移除输出并隔离版本 | 权限与页面源复核 |
| 资源加载拖慢主要内容 | 受影响页面集合 | 延后或关闭第三方入口 | 资源预算和错误日志清晰 |
| 主题检查无法解释 | 变更版本 | 不继续扩大范围 | 规则、版本、差异可复现 |
17. 维护节奏与可执行的运行手册
17.1 小步维护而不是大批重写
每次维护先选择一个页面族和一个可观察结果。先保存基线,再改动,再执行同一矩阵;如果同时改变模板、应用、翻译和资源,就无法知道哪个变化造成差异。清理旧 snippet 前,先搜索调用方和设置键,保留迁移说明;删除应用 block 前,确认卸载后的主题不会留下脚本、样式或空容器。
运行手册要写出发现问题时的第一步、隔离开关、上一个可用版本、证据位置、通知角色和恢复后的复测项。它面向值班人员,不应要求读者理解所有 Liquid 细节。每次故障结束后更新手册和 fixture,让同类问题可以在下次检查中更早出现。
17.2 定期检查事实是否仍然成立
Shopify 平台、主题工具、应用扩展配置和浏览器行为会变化。定期检查官方文档链接、CLI 安装版本、Theme Check 规则、应用扩展资源、语言清单和性能预算;如果事实随版本或地区变化,记录重新确认的日期和责任人。不要把旧命令、旧字段或旧截图当作永久契约。
把维护结果分为“继续使用、需要复查、需要隔离”三种状态,并保留每种状态的证据。文章中的流程可以帮助团队建立检查,但真正的主题版本仍要在自己的开发主题、代表性数据和允许的权限范围内验证。进一步的性能、Liquid 和扩展边界可分别参考主题开发与维护运营、Liquid 架构实践和主题应用扩展治理等配套主题。
常见问题
FAQ 1:Shopify 主题开发应该从 Liquid 还是 JSON 模板开始?
先从用户任务、页面类型和数据边界开始,再决定 Liquid 与 JSON 模板的顺序。若页面组合和商家编辑能力尚未定义,直接写 Liquid 会把错误的职责固化;若对象字段、空状态和输出语义已明确,可以先写最小 section,再用 JSON 模板组合和验收。
FAQ 2:应用 block 可以直接复制到主题文件里吗?
不建议。应用扩展拥有自己的配置和生命周期,主题应提供放置位置、布局降级和必要设置,而不是复制应用内部代码。验证应用启用、空结果、超时、禁用和移除后的页面;若卸载后仍有脚本或样式,需要由应用 owner 清理扩展边界。
FAQ 3:没有 JavaScript 时主题必须完整可用吗?
核心阅读、导航、表单语义和主要操作应有可理解的基础状态,增强交互失败时要有错误说明或替代路径。并非每个动态推荐都能在无脚本时复现,但不能因为脚本失败而丢失商品事实、主要链接或焦点可达性。把无脚本页面作为矩阵中的独立样例。
FAQ 4:性能预算是不是 Shopify 页面速度的保证?
不是。预算是团队在固定测试条件下控制资源和长任务的验收门槛,不能保证所有网络、设备、应用响应或用户结果。记录页面、数据、设备、资源和测量时间;超出预算时定位具体资源,选择拆分、延后、替换或隔离,并在相同条件下复测。
FAQ 5:什么时候应该恢复上一个主题版本?
当核心导航、购物车、表单、键盘路径、语言 URL、敏感信息或大量页面的主要内容受到影响,且无法在隔离模块中快速证明安全时,应优先恢复上一个可用版本。回退前保存失败差异和日志;回退后复测代表性页面、应用开关、语言和设置,确认问题消失且没有引入新的空状态。
官方一手资料
以下资料用于核对主题架构、CLI、Theme Check、性能、应用扩展、可访问性和版本控制;文档中的资格、字段、规则和工具行为可能随版本变化,使用前应在自己的开发主题和权限范围内复核。