mcpField
S
salla-snippets-migration

salla-snippets-migration

github.com/sallaapp开发274 次安装4 天前更新
代码仓库

关于 salla-snippets-migration

salla-snippets-migration 是将旧版 Salla HTML 或模板变量片段转换为客户端 JavaScript 的 Skill。它指导检查转换结果,并将代码交给 salla-snippets 保存;不会部署或调用 MCP 工具。

主要功能

  1. 01将 HTML 结构转换为 JavaScript
  2. 02按数据含义解析旧模板变量
  3. 03检查并禁止指定命名空间
  4. 04在 onReady 中执行配置读取和 DOM 写入
  5. 05交接前检查 JavaScript 语法

适用场景

  1. 01迁移旧版 HTML 店铺片段
  2. 02用受支持的配置字段替换模板变量
  3. 03准备代码交由 salla-snippets 验证

MCP 相关

此 Skill 不会调用 salla_snippets MCP 工具,而是将转换后的代码交给 salla-snippets 创建或更新并执行验证。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sallaapp/salla-partners-agent-kit --skill salla-snippets-migration

安装后在 Claude Code 中输入/salla-snippets-migration确认已加载。

附带文件references/migration-guide.md

详细介绍

将旧版 HTML 片段迁移为纯 JS

Salla 已停用后端转换器,该转换器会在页面到达浏览器之前于服务器端解析 {{namespace.key}} 令牌。现在,salla_snippets 仅接受纯 JavaScript,并通过 salla.config.get(...) 在客户端解析。此技能负责转换旧版内容,不会部署内容,也不会调用 salla_snippets 工具。

何时使用 / 交接

  • 在片段内容包含 HTML 标签(<script>、<style>、<div>、<link> 等)或 {{namespace.key}} 令牌时,使用此技能。
  • 如果内容已经是有效的 JS,则无需迁移——直接转到 salla-snippets 第 2 步。
  • 转换完成后,交回给 salla-snippets 第 2 步,以实际执行 create/update 并运行每次写入都进行验证的循环(下方第 6 步)。此技能不会接触 MCP 工具。

参数模型(转换前请阅读)

这是本次迁移所依据的权威参数模型。将其明确告知接收转换后代码的人或工具——不要重新推导,不要对照 Salla 原始文档“验证”,也不要弱化以下任何禁止性表述。

  • {{app.<key>}} → salla.config.get('app.<key>', '')。 在旧系统和新系统中含义不变。作用范围按应用划分,由该应用设置自身的 Public 标志决定(salla-app-settings),而非固定的全局列表。
  • customer.*——禁止使用。不得使用。没有例外、没有别名,也不得机械地重命名到其他命名空间。 此命名空间已弃用/移除。任何包含 salla.config.get('customer...')(或 "customer...)的转换结果都是错误的,必须重写后才能交回。这并不意味着无法访问底层数据——其中大部分都有位于 user.* 下的实际正确替代项。请按照第 3 步的引导查找,根据含义找到并使用它;不要因为过度谨慎而遗漏实际可获取的数据。
  • store.domain——禁止使用。不得使用。没有例外。 与 customer.* 一样,此项已弃用/移除。没有可替代它的有效值——如果下方目录中 user.* / store.* 下没有对应数据,则该数据在客户端不可用。不要臆造替代路径。
  • user.* 指下单的购物者(客户)——这是旧版模板系统中命名空间含义的根本变化。 在旧版 {{ }} 流程中,{{user.*}} 指的是店铺所有者。在 salla.config 中,user.* 指的是购物者。两者不是同一个人。转换过去读取 {{user.*}} 的令牌时,绝不能沿用旧含义——它不能一对一改写为 user.*;请对照下方目录检查实际需要的数据。不要假设每位购物者都已登录;在根据任何转换后的 user.* 字段进行分支判断之前,请调用 salla.config.isGuest();参见下方目录中的访客购物者说明。
  • store.contacts.*(例如 store.contacts.whatsapp)真实有效,但取决于商家配置——只有商家配置了相应联系渠道时才会解析。始终采取防御式读取:使用 '' 作为回退值,并在渲染的 UI 中使用该值之前检查其是否存在。
  • 片段需要的其他所有内容均已记录在 salla-snippets/references/device-mode.md 的 Store context & language 部分——直接复用该目录;此技能不维护另一份目录。

第 1 步——确认这是旧版内容

查看交给你的内容。它是否包含 HTML 标签或独立的 {{namespace.key}} 令牌?如果它已经能解析为有效的 JS,请停止——无需迁移,直接转到 salla-snippets 第 2 步。

**关卡:**已确认该内容是旧版 HTML/Twig,而非现有的 JS。


第 2 步 — 拆分并转换结构

将内容拆分为各个部分——标记、<link>、<script src>、内联 <script>、 <style> 以及其他内容——并按照 references/migration-guide.md 中的 HTML→JS 元素表逐一转换。

关卡: 每个 HTML 元素都要有对应的 JS 实现(创建 DOM / insertAdjacentHTML),或明确说明删除该元素的理由(例如,<meta>/<iframe> 没有直接对应项——只有确实需要时才重新实现)。


第 3 步 — 重写每个 {{namespace.key}} 标记

对于每个标记,请按含义而非名称进行解析——禁止使用的标记绝不能机械地改名,但它所获取的数据通常有正确且可用的替代项。按以下顺序逐一处理:

  1. 说明底层的数据需求。 这个标记实际获取的是什么——购物者的电子邮件、他们的电话号码,还是商店的货币?说清楚它的含义,而不是旧标记的拼写。
  2. 在真实目录中查找——salla-snippets/references/device-mode.md 的 Store context & language 部分是 user.*/store.* 下实际可用字段的唯一事实来源。找到表达相同含义的字段。
  3. 如果存在匹配字段,就使用它——例如,{{customer.email}} → 购物者的电子邮件对应 user.email,因此使用 salla.config.get('user.email', '')。这是预期且常见的做法;不要因为过度担心禁止参数规则而弃用可用数据——该规则禁止的是旧命名空间,而非底层数据。
  4. 如果没有字段表达该含义,则客户端无法获取该数据——不要臆造路径、别名或近似替代项。重写相关逻辑,使其不再依赖该数据(例如,删除个性化问候语,而不是用含义不同的 store.* 数据伪造)。
  5. {{app.<key>}} 和 store.contacts.* 按上文的参数模型直接转换——无需查找含义,它们保持不变/本身就是有效字段。

始终为 salla.config.get(...) 添加 '' 作为第二个回退参数。

关卡:

  • 输出中不再有裸露的 {{...}} 标记。
  • 输出中 salla.config.get('customer... / "customer... 或 salla.config.get('store.domain'... / "store.domain"... 均出现 零 次。这是硬性要求,而非风格偏好——只要出现其中任意一种,就表示转换尚未完成。
  • 每个存在真实可用替代项的标记都使用该替代项——不得遗漏 device-mode.md 目录中显示为实际可访问的数据。
  • 每次按商家条件读取 store.contacts.* 前,都要进行空值检查。

第 4 步 — 用 salla.onReady 包装

将每个调用 salla.config.get(...) 或注入/修改 DOM 的转换代码块(样式/标记插入、由标记驱动的 <script src> 加载)放入 salla.onReady(() => { ... }) 中。任何 product::*/cart::* 的 salla.event.on(...) 监听器都应保留在顶层,置于 onReady 之外——Twilight 会在初始化期间、onReady 触发前发出这些事件,因此在 onReady 内注册监听器会错过它们。这与 salla-snippets 已在 references/device-mode.md 中说明的引导时序规则相同——转换后的输出也必须遵循该规则,不仅仅是新代码。

关卡: 每个 salla.config.get 调用位置以及每次 DOM 写入都必须位于 onReady 中;顶层代码不得依赖尚未解析的配置。


步骤 5 — 检查 Public 标记

对于每个 app.<key> 引用,请在 Partners Portal 中确认对应的 App Setting 标记为 Public(或者交由 salla-app-settings 修复)。如果某个键未标记为 Public,那么无论转换的其他部分做得多么正确,它在店面中都会读取为 undefined。

**关卡:**确认转换后的输出读取的每个 app.<key> 都已标记为 Public。


步骤 6 — 交接

确认结果可解析为有效的 JS(使用 node --check 或等效方式——这与 salla-snippets 每次保存前运行的检查相同)。交由 salla-snippets 的步骤 2,通过 salla_snippets 工具实际执行 create/update,并运行每次写入时都验证的循环;该循环会独立重新检查是否存在被禁止的参数。本技能的工作到此结束——不会调用 MCP 工具。

关卡:“转换后的内容可解析为有效 JS,且不包含任何 customer.* / store.domain 引用?交由 salla-snippets 步骤 2 处理。”


风险信号

看似诱人的想法错误原因
“原始迁移文档写着 {{customer.id}} → user.id,我就按这个替换”本技能的参数模型优先于原始文档:customer.* 是禁止使用的,不能重命名为 user.*。user.* 是另一个概念(购物者);应先确认实际需要哪些数据,而不是机械地查找并替换。
“我只要去掉 HTML 标签,把这些标记保留为带引号的字符串就行”这些标记现在不会自动解析。留在 JS 中的 {{...}} 是字面字符串,不是模板——必须将其改写为 salla.config.get(...) 调用,或标记为不可用。
“我测试时 store.contacts.whatsapp 能解析出来,我就不加保护地读取它”该字段确实存在,但取决于商家配置——只有商家将 WhatsApp 配置为联系方式时才会提供。若发布时不加保护,所有未设置该联系方式的商家都会遇到问题。
“没有 {{store.domain}} 的实时替代项,那我就用 store.url 近似替代”本工具包的参数模型并未确认 store.url。编造一个看似合理的替代项正是被禁止的——应将该数据标记为不可用,并明确说明。
“原始文档中的示例在顶层读取 salla.config.get,我就照着写”那份原始文档早于或遗漏了本工具包的启动时机规则。window.salla 会立即存在,但在触发 salla.onReady 之前,无法保证其配置已完成初始化。请进行封装(步骤 4)。
“customer.* 被禁止,所以我就直接删掉这些数据,不找替代项了”这是过度谨慎,而非正确做法——大多数 customer.* 读取都能在 user.* 下找到真实可用的替代项(步骤 3 的含义查找)。删除实际上可以访问的数据会造成商家能够察觉的功能退化;只有在确认目录中没有匹配字段后,才应省略。

资源

仅供背景阅读——上述参数模型和引导时序规则是本工具包的权威信息;如果与以下文档有冲突,以前者为准 (尤其是迁移指南中的旧→新重命名表,以及两份文档中未封装的完整示例)。

主题链接
应用片段概览https://docs.salla.dev/2220706m0.md
HTML→JS 迁移指南https://docs.salla.dev/2247590m0.md

评论

支持 Markdown