ESA Pages 体验之旅(5):修复 TableStore SDK 的变量声明错误
TableStore Node SDK 进入 ESM 函数产物后,在未声明的变量赋值处抛出 ReferenceError。ESM 采用严格模式,原先可能隐式创建全局变量的写法在这里被拒绝,需要修正 SDK 的声明。
修复涉及三个文件、六处声明,补上 var 即可。仓库里同时存在协议生成代码和浏览器 bundle,因此先确认待改文件的来源,避免修改会被重新生成的产物。
SDK 实现和生成文件
本次核对固定公开仓库 master 提交 39d4dae43ed73fc97cad5bff3d634d926a8ce1bf、仓库版本 5.6.4,以及实际使用的 npm 5.6.6。仓库是阿里云官方 TableStore Node SDK。
| 文件或脚本 | 公开仓库能确认的职责 |
|---|---|
lib/filter.js 等实现文件 |
Git 历史直接维护的 JavaScript |
build_proto.sh |
调用 pbjs、flatc,从协议定义生成相应代码 |
| 浏览器构建 | Browserify / Uglify 生成浏览器分发包 |
| package.json | 当前没有把 TS 或 Babel 源码编成整个 lib 的构建流程 |
公开 Git 历史直接维护这些 JavaScript 文件,部分文件还使用 const、let 与解构。公开仓库没有展示一套将 TS 或 Babel 源码编译为整个 lib 的流程;内部是否另有源码,现有材料无法确认。
待修复的三个文件不由协议生成命令产生,实际修改的是这些 JavaScript 实现文件。
npm 发布包与 GitHub 的差异
npm 5.6.4 的 lib 文件在统一换行后与该 Git 提交一致。5.6.6 则有九个 lib 文件不同,但待修复的 filter、PlainBuffer builder 仍相同,encoder 虽有其他更新,缺变量声明的位置也仍存在。
5.6.6 的 gitHead 指向 6fbfb291ab4268d47934ddb3a39fac6416a71bad,公开 GitHub 查询返回 422、No commit found。发布包与可见 Git 历史存在同步差异,尚缺对应的公开维护版本。完整版本、文件散列与查询结果见源码与发布包核对记录弹窗。
npm 5.6.6 的这些更新未同步到本次查到的公开 GitHub 版本,因此暂不向旧版 master 提交 PR。直接在旧分支上修改,无法确认补丁与当前发布版本的对应关系。问题先通过阿里云官方售后反馈,待对应源码公开或维护者明确接收分支后,再考虑 PR。
补齐六处变量声明
| 文件 | 缺失声明 |
|---|---|
lib/filter.js |
三个 pro 循环变量 |
lib/protocol/encoder.js |
一个 sub 循环变量 |
lib/protocol/plian_buffer_builder.js |
一个 key 循环变量和一个 size 赋值 |
下面是相同机制的简化片段:
// 修复前:严格模式下,pro 未声明。
for (pro in properties) {
// ...
}
// 修复后:沿用 SDK 现有的 var 风格。
for (var pro in properties) {
// ...
}
原代码在非严格 CommonJS 环境中,可能将这些名字写进全局对象。严格模式拒绝这种赋值,错误才变得可见。给宿主补同名全局变量,会继续保留共享状态污染;改成非严格模式,也没有修掉缺陷。
缺失声明可以追到 2017-06-15 的初始实现提交 45e4c44f9ae3fea0010ec4124da98bb66039dca9,提交信息为 add node.js sdk。缺陷长期存在,严格模式让它在这次产物中暴露出来。
复用已有的编解码测试
SDK 已有 PlainBuffer 编解码测试。使用原始 CommonJS 加载时,两项测试通过;将涉及的三个实现文件按严格模式加载时,原代码在 key 处报错,补声明后两项又通过。
这两项既有测试经过了缺陷位置,修复后编码结果保持一致。验证范围限于这些 PlainBuffer 路径。默认的 mocha test 不递归覆盖所有子目录,test/protocol 中的用例需要明确执行。完整命令和结果见既有功能测试对照弹窗。
长期防止再次漏声明,适合使用 no-undef 这样的静态规则;功能测试继续验证编码、过滤和协议结果。无需为每个补上的 var 各写一个只检查源码文字的测试。接入 lint 时仍需登记真实宿主全局,避免把隐式变量误列为合法全局。
用依赖补丁保存修复
应用仍然安装 npm 发布的 SDK,可以用包管理器的补丁机制保存这六处修复。直接改 node_modules 只能影响当前安装;生成补丁并纳入版本管理,才能让其他设备、CI 和下一次安装得到相同结果。
本项目使用 pnpm,已经通过原生补丁机制维护 tablestore@5.6.6。创建或更新补丁时,先运行:
pnpm patch tablestore@5.6.6
在命令给出的临时目录里修改 SDK,再将这个目录路径传给 pnpm patch-commit。它会生成补丁文件并登记 patchedDependencies。当前修复保存在 patches/tablestore@5.6.6.patch,由 pnpm-workspace.yaml 引用;补丁、配置与锁文件一起提交,依赖安装时应用修复。具体命令见 pnpm patch 和 patch-commit。
使用 npm 或 Yarn Classic 的项目,也可以用 patch-package:修改已安装的包后生成 patches 文件,并配置 postinstall 在安装后重新应用。补丁与安装脚本同样需要进入仓库,部署构建时还要确认没有跳过这一步。pnpm 已有原生能力,本项目不再额外引入 patch-package。
补丁针对具体发布版本保存。升级 SDK 时应重新检查差异,不能因为旧补丁仍能应用,就认定新版本仍然需要这些修改。
等待官方修复
这组缺少变量声明的问题已经向阿里云官方售后反馈,目前先保留依赖补丁。后续如果官方发布修复版本,先核对发布包是否补齐这六处声明,再在不应用该补丁的条件下,运行既有功能用例和最终 ESM 产物验证。
确认新发布包修复这些声明后,再升级依赖,删除 TableStore 的补丁文件及 patchedDependencies 对应配置,更新锁文件,并用干净安装复查。
这里撤除的是 SDK 变量声明补丁。ESA 的模块加载、网络传输和其他兼容处理,需要分别判断是否仍然必要。
SDK 的环境依赖
这份补丁修复了 SDK 的变量声明。签名、二进制编码、URL 与网络传输还依赖宿主 API,需要在最终产物中继续验证。SDK 能通过严格模式检查以后,仍可能在初始化或实际调用时遇到环境差异。
TableStore 源码与 npm 发布包核对记录
包含固定 Git 提交、包版本、文件散列、生成脚本,以及 npm 5.6.6 的 gitHead 查询结果。
既有 PlainBuffer 功能测试与严格模式对照
使用仓库已有编解码用例比较原始加载、严格模式和补声明后的结果。数据保留实际命令与失败位置,不把这两项测试当成全 SDK 回归。