每家 Shopify 店铺都会装应用,而每个碰触前端的应用迟早向你的主题讨一个人情:插一段代码、加一个 script tag、“就给这个应用加一个区块”。每个人情都是一个补丁——补丁就是主题腐烂的方式。Theme App Extensions(TAE)就是终结这个循环的契约:应用交付自包含的区块与资源,主题通过稳定的锚点渲染它们,双方都不伸手进对方的内部。这篇文章讲如何设计这份契约,以及如何处理主题里已有的历史补丁。
应用区块为什么会弄坏主题
老办法是应用装一个 script tag,或商家“按客服指示”往 theme.liquid 粘代码。问题随之叠加:脚本每页都加载,不管功能用不用得上——页面体积、LCP 影响、脚本冲突;针对 .product-form 的写死选择器在主题更新标记后失效,商家找客服、客服怪主题、主题开发者发现一段不是自己写的代码;卸载应用后代码残留,没人知道哪个补丁属于哪个应用。
TAE 修正了机制:应用区块是应用控制的 Liquid 渲染(访问限于白名单的 Liquid 对象与过滤器),资源只在区块渲染处加载,安装、更新、卸载都由 Shopify 处理。这是沙箱。但沙箱不是契约——主题要定义锚点,应用要尊重锚点。
设计扩展契约
主题一侧:把区块渲染在它该在的地方,而不是方便的地方。 定义稳定的锚点(sections 与区块,标记经得起改版),对每个锚点声明:可用的 Liquid 对象(product、cart、collection、customer)、现成的 CSS 钩子、主题提供什么不提供什么。主题把应用区块当不透明对象:渲染,不重排、不伸手进内部。你的责任是布局和锚点稳定,不是应用内部。
应用一侧:区块必须自包含。 自带作用域到区块的 JS/CSS,资源走扩展自己的 asset URL 而不是内联在模板里;除声明的钩子外,不依赖主题的全局样式或 DOM 结构;合适处用 {{ block.shopify_attributes }};诚实地声明能力——需要 product 上下文就声明,商家不该通过故障来发现。
区块 schema 是契约的一部分。 blocks/ 目录里的模板与 settings 决定商家能配置什么。保持设置可枚举、有类型——复选框、下拉框、带校验的输入——让商家能做的每个配置都是渲染代码能处理的。一个接受任意文本的 settings 字段,是一份等待违约的契约。
契约落地:检查你的主题
theme.liquid或布局里有没有 script tag 或注入片段? 每个都是历史补丁:查清归属,看那个应用是否提供 TAE,有就迁移区块、删掉补丁。- sections 有没有稳定、有文档的锚点给应用区块? 给它们可预期的位置,CSS 钩子跨版本不变。
- 主题 CSS 是否在跟应用区块打架? 激进的全局 reset 作用到
.shopify-section,就是在跟每个渲染在那里的应用打架,收窄作用域。 - 应用被移除时会发生什么? TAE 下移除是干净的——卸载后主题应正常渲染、无残留代码。
什么时候需要外部帮助
如果主题背着多年累积的补丁——说不清归属的 script tag、不敢删的片段、跟 CSS 打架的应用区块——一次主题审计可以把补丁映射到主人、把应用集成放到 TAE 契约上,赶在下一次应用更新弄坏店铺之前。如果从零建主题,预先定义锚点是一笔小投资,回报在未来的每一次集成里。无论哪种情况:应用应该是你主题的客人,而不是房客——一次有边界的 Commerce Architecture Review 可以产出这份契约和迁移计划。