十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

修复 npm `file:` 本地 tarball 依赖的陈旧性陷阱:@fhevm/sdk 多测试平台内容寻址重打包方案解析

修复 npm `file:` 本地 tarball 依赖的陈旧性陷阱:@fhevm/sdk 多测试平台内容寻址重打包方案解析 修复 npmfile:本地 tarball 依赖的陈旧性陷阱fhevm/sdk 多测试平台内容寻址重打包方案解析【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm导读在 fhEVM 的 JavaScript SDKsdk/js-sdk中测试平台test/browser-next曾出现过一种隐蔽故障源码与刚打好的 tarball 都是新版本但 Turbopack 打包进浏览器的却是旧构建导致 TFHE 多线程初始化以TypeError: __turbopack_context__.x is not a function失败而npm run build/npm run test全程绿灯。根因在于 npm 对file:本地 tarball 依赖按固定版本号解析缓存重打包后版本号不变消费者节点树便跳过重新解压。本文完整解析仓库中的修复方案 TARBALL_FRESHNESS_FIX_PLAN.md——Option A内容寻址content-hashedtarball 命名并对照仓库源码逐项拆解其六个工作项、被否决的备选方案与验证方法读者可据此在自己的多平台消费场景中根治同类陈旧依赖问题。一、问题症状mtcoop单元在 browser-next 上命中陈旧 SDK1.1 现象与报错现场test/browser-next在运行 TFHE 的mtcoop多线程 跨源隔离单元时命中了陈旧的fhevm/sdkworker 修复已存在于源码与刚打好的 tarball 中但 Turbopack 实际打包的副本是修复前的构建MT 初始化因此失败报错如下[FAIL] All worker creation methods failed [cause] TypeError: __turbopack_context__.x is not a function at __newNodeWorkerFromJsCode -- old __isBrowserLike() → Node worker path in the browser出错位置__newNodeWorkerFromJsCode指向旧版__isBrowserLike()判定逻辑旧构建在浏览器环境错误地走了 Node worker 分支而新构建已修复该判定。1.2 为什么 CI 是绿的原文档明确指出两条掩盖路径仓库源码可以印证npm run build/npm run test不覆盖 Next 平台查看 package.json 中test脚本它依次执行test:unit、test:localcleartext:pack:v12、test:localcleartext:pack:v13与test:browser-smoketest:browser-next是独立脚本npm run pack:prod npm run browser-next:refresh-sdk ./test/browser-next/run-tests.sh不包含在默认test里。单线程模式不会触发 workerbrowser-next的加密页 app/encrypt/page.jsx 中THREADS process.env.NEXT_PUBLIC_FHEVM_TEST_THREADS ?? st只有mt多线程才把numberOfThreads设为MT_THREAD_COUNT0st模式恒为 0、根本不 spawn worker因此陈旧代码在单线程下静默通过。也就是说该缺陷只会在多线程 跨源隔离 走打包产物的组合路径上爆发而这条路径恰好是 CI 常规流程不覆盖的盲区。二、根因分析npm 对file:tarball 的版本解析缓存2.1 单一 tarball 被多个node_modules树消费原文档给出的核心事实是一个恒定名称 恒定版本的 tarball形如fhevm-sdk-1.1.0-alpha.5.tgz被多个相互独立的node_modules树消费消费者依赖声明重打包后是否刷新test/manual-packfile:fhevm-sdk-1.1.0-alpha.5.tgz是rebuild_sdk_and_pack.sh会清掉其node_modules与 lockfiletest/browser-nextfile:../manual-pack/fhevm-sdk-1.1.0-alpha.5.tgz否对照仓库现状rebuild_sdk_and_pack.sh在 sdk/js-sdk/test/scripts/rebuild_sdk_and_pack.sh 中打完包后会rm -rf $PACK_DIR/node_modules $PACK_DIR/package-lock.json再重新npm install所以manual-pack总是新鲜的而browser-next的依赖声明见 test/browser-next/package.json指向file:../manual-pack/fhevm-sdk-*.tgz重打包脚本从不触碰它。2.2 npm 的解析语义按 resolved version 缓存npm 对file:tarball 的安装以resolved version为键版本号在两次重打包之间从不变化browser-next执行npm install时看到依赖已满足已有旧解压 lockfile 钉住了旧 integrity直接跳过重新解压即使run.mjs --rebuild会调用npm installnpm 也只是 no-opshouldInstall()见 test/browser-next/scripts/run.mjs只检查node_modules/fhevm/sdk/package.json、next、react等是否存在从不检查是否新鲜因此无法发现此问题。这里还值得注意一个仓库现状中的细节browser-next/package.json当前引用的是fhevm-sdk-1.1.0-alpha.6.tgz而run.mjs里硬编码的tarballPath仍是fhevm-sdk-1.1.0-alpha.5.tgz——两个文件对同一个 tarball的引用已经出现版本漂移这正从侧面印证了固定名称 固定版本这种约定在多个消费者之间的脆弱性。2.3 现有缓解手段的局限仓库中已经存在一个针对性的缓解脚本 test/browser-next/refresh-sdk.sh它会杀掉:3334上的 Next 开发服务器、rm -rf node_modules/fhevm/sdk后用npm install --no-save tarball强制重装。但它有两个明显缺陷一是依赖记得手动执行test:browser-next脚本链中虽已接入但其他入口容易漏掉二是它靠删除目录 --no-save规避缓存属于cache-busting 技巧并不改变 tarball 无唯一标识这一根本问题。原文档的方案正是要替换掉这类脆弱的绕行手段。三、修复目标原文档明确了修复后的三条验收标准这也是后续设计每项工作必须满足的约束确定性执行一次rebuild_sdk_and_pack.sh后每个消费 tarball 的测试平台都保证运行刚构建的 SDK失败要响亮陈旧的安装必须大声失败hard fail而不是静默跑旧代码避免无谓重打包当 SDK 内容未变化时重打包应被跳过性能优化。四、方案设计Option A —— 内容寻址 tarball 命名4.1 核心思想给每个新打出的 tarball 一个新身份在文件名中嵌入短内容哈希得到fhevm-sdk-ver-sha8.tgz。这样每个消费者的file:依赖字符串随之改变npm 会重新解析并重新解压——不再依赖任何 cache-busting 技巧文件名本身就是当前装的是哪个构建的直观标识可一眼检查。4.2 被否决的备选方案及理由原文档明确记录了两个被否决的替代方案理解它们有助于把握方案边界file:../../src直连源码 /npm link绕过 tarball也就不再验证发布产物的形态exportsmap、files白名单、打包进 tarball 的 wasm 等发布前拦截能力归零直接 bump 真实发布版本号为了一个测试工程问题去污染发布版本号代价不划算。这两条否决意见解释了为什么方案必须落在tarball 自身命名这个层面而不是换一种安装方式或改版本号。五、工作项逐项拆解5.1 工作项 1消费者注册表单一事实来源在 test/scripts/rebuild_sdk_and_pack.sh 中一次性声明全部消费者# Dirs whose package.json has fhevm/sdk: file:.../fhevm-sdk-*.tgz. CONSUMERS($ROOT_DIR/test/manual-pack $ROOT_DIR/test/browser-next)也可改为自动发现让未来新增的测试平台无需改动脚本即被纳入mapfile -t CONSUMERS (grep -rl fhevm-sdk-.*\.tgz $ROOT_DIR/test \ --includepackage.json | grep -v node_modules | xargs -n1 dirname)两点说明manual-pack的特殊之处仅在于它的 tarball 就位于其目录内部其他消费者通过相对路径引用它。当前rebuild_sdk_and_pack.sh里PACK_DIR$SCRIPT_DIR/../$MANUAL_PACK_DIRNAME正是这种内嵌布局自动发现用grep -rl fhevm-sdk-.*\.tgz --includepackage.json扫描package.json并排除node_modules比手工维护列表更不易遗漏。5.2 工作项 2对 tarball 做内容哈希并重命名在npm pack产出fhevm-sdk-ver.tgz之后RAW_TARBALL$(echo $PACK_DIR/fhevm-sdk-*.tgz) VER$(node -p require($ROOT_DIR/src/package.json).version) SHA8$(shasum -a 256 $RAW_TARBALL | cut -c1-8) TARBALL_NAMEfhevm-sdk-${VER}-${SHA8}.tgz mv $RAW_TARBALL $PACK_DIR/$TARBALL_NAME同时脚本顶部的rm -f $PACK_DIR/fhevm-sdk-*.tgz会先清掉上一次的哈希 tarball保证同一时刻只存在一个。需要强调的设计意图原文档特别注释哈希的是 tarball 本体而非dist/。因为 tarball 正是将被安装的字节哈希它就是哈希实际会运行什么身份刻画最忠实。npm pack在当前场景下已足够确定性若未来出现 pack 期不确定因素如时间戳再退化为对dist/输入做哈希并把结果印进文件名。5.3 工作项 3重写每个消费者的file:依赖对每个消费者把fhevm/sdk指向新哈希后的 tarball相对路径按各消费者位置换算使用一个小的 Node 助手做健壮的 JSON 编辑for c in ${CONSUMERS[]}; do node $SCRIPT_DIR/set-sdk-dep.mjs $c/package.json $(rel_to $c $PACK_DIR/$TARBALL_NAME) doneset-sdk-dep.mjs新增脚本的职责很单纯读 JSON → 设dependencies[fhevm/sdk] file: relPath→ 写回。manual-pack/package.json保持裸文件名形式file:name.tgz它的重写逻辑并入同一个循环即可当前 rebuild_sdk_and_pack.sh 里正是用cat $PACK_DIR/package.json整体覆写manual-pack/package.json其中fhevm/sdk: file:${TARBALL_NAME}。5.4 工作项 4按消费者强制重新解压不误伤无关依赖for c in ${CONSUMERS[]}; do rm -rf $c/node_modules/fhevm/sdk # drop the old extraction (cd $c npm install) # re-resolves the changed file: spec donemanual-pack可以保留它现有的rm -rf node_modules package-lock.json目录小、全量重装代价低browser-next绝不能整目录清空否则会丢掉next/react等重依赖。只删node_modules/fhevm/sdk再npm install就足够因为第 3 步已经改了依赖字符串lockfile 条目会被重写而非复用。5.5 工作项 5新鲜度守卫耐久性关键新增test/scripts/assert-fresh-sdk.mjs逻辑如下从消费者的package.json解析其fhevm/sdk的file:目标分别对tarball 内与已安装副本中的哨兵文件做 sha256tarball 内package/wasm/tfhe/v1.6.1/startWorkers.js已安装node_modules/fhevm/sdk/wasm/tfhe/v1.6.1/startWorkers.js哈希不一致或安装缺失即throw并给出可执行提示fhevm/sdk in consumer is stale (installed ! packed). Run: npm run test -- --rebuild调用点有两处构成双重保险test/browser-next/globalSetup.ts任何 spec 运行之前——注意当前 globalSetup.ts 的职责是拉起 anvils 与 gateway守卫应叠加在它开头test/browser-next/scripts/run.mjs中 install 步骤之后。原文档强调即使未来某个 npm 版本改变了缓存行为守卫也能把整个静默运行旧 SDK的故障类转换成硬性、可行动的报错。关于哨兵路径文档示例为v1.6.1对照当前仓库 src/wasm/tfhe 实际存在v1.5.3、v1.6.0-dev、v1.6.2等版本目录实现时哨兵路径应指向当前打包实际携带的 TFHE wasm 版本目录下的startWorkers.js。5.6 工作项 6条件重打包快速开发循环的性能优化替换run.mjs中只查存在性的shouldInstall()改为指纹比对SDK 未变化时跳过约 24 MB 的重打包指纹算法git rev-parse HEAD:srcsrc/与scripts/wasm/的 dirty 哈希或对这两个路径执行git status --porcelain打包时把指纹写入test/manual-pack/.sdk-fingerprint与 tarball 并列存放rebuild_sdk_and_pack.sh若当前指纹与已存指纹一致且 tarball 存在则跳过 buildpack除非--rebuild/--build-profile强制run.mjs仅在指纹不同或--rebuild时才重打包但新鲜度守卫工作项 5无论何种情况都执行——它很廉价却是耐久性的保证。当前run.mjs的shouldInstall()逐项检查fhevm/sdk、ethers、next、react、react-dom五个包的package.json是否存在test/browser-next/scripts/run.mjs正是只问存在、不问新鲜的典型实现工作项 6 直接替换它。六、涉及文件清单原文档给出完整的改动面结合仓库路径整理如下文件仓库根相对路径改动sdk/js-sdk/test/scripts/rebuild_sdk_and_pack.sh消费者注册表哈希并重命名 tarball重写各消费者file:依赖按消费者强制重装写.sdk-fingerprint未变化时跳过sdk/js-sdk/test/scripts/set-sdk-dep.mjs新增重写消费者package.json中fhevm/sdk的file:依赖sdk/js-sdk/test/scripts/assert-fresh-sdk.mjs新增已安装副本 vs tarball 的新鲜度守卫sdk/js-sdk/test/browser-next/scripts/run.mjs基于指纹的重打包/安装判定调用守卫sdk/js-sdk/test/browser-next/globalSetup.tsspecs 前调用守卫sdk/js-sdk/test/browser-next/package.json、test/manual-pack/package.jsonfile:依赖由脚本改写为哈希 tarball 名提交一次此后自动更新七、最小核心 vs 完整方案原文档给出了清晰的取舍梯度耐久核心根治该故障类工作项 1–5。其中 1 提供消费方单一事实来源2/3/4 完成改名 → 改引用 → 重装的闭环5 提供失败必须响亮的兜底性能精化工作项 6指纹跳过重打包最小可行改动工作项 2 3 4 5——哈希命名 重写依赖 全消费者重装 守卫即足以修复问题的最小集合。八、验证方法按原文档步骤执行bash test/scripts/rebuild_sdk_and_pack.sh --build-profiledev期望结果manual-pack下只存在一个fhevm-sdk-ver-sha8.tgz两个消费者的依赖均指向该 tarball两者的node_modules/fhevm/sdk都被重新解压。运行多线程 跨源隔离单元cd test/browser-next FHEVM_TEST_THREADSmt FHEVM_TEST_COOP1 \ npx playwright test specs/encrypt.spec.ts期望通过numberOfThreads2产生 proof证明修复实际被跑到了。该 spec 对应 specs/encrypt.spec.ts其核心断言是页面#result的data-status为pass120 秒超时在 run-tests.sh 的 CELLS 表中encrypt viem (mt, coop)正是文档描述的那个mtcoop单元encrypt.spec.ts|viem|mt|1。负向测试手工改动已安装的startWorkers.js后运行守卫必须大声失败。SDK 无变化时重跑工作项 6 应跳过重打包守卫仍然通过。九、设计要点的工程启示从这份修复计划可以提炼出几条对任何以 tarball 为交付物、多平台消费的工程都可复用的结论file:tarball 的版本解析是身份而非内容的缓存——只要名称版本不变npm 就认为依赖已满足。给产物引入内容哈希身份是把缓存键从声明变成内容的通用解法存在性检查 ≠ 新鲜性检查——shouldInstall()这类目录在不在的判断永远防不住目录在但是旧的守卫必须比较将要运行的字节与已安装的字节对 tarball 本体哈希正是为此测试平台越接近真实发布形态越有价值——被否决的file:../../src/npm link之所以不可取是因为它们绕过了对发布产物exportsmap、files白名单、内嵌 wasm的验证本次方案坚持让每个测试平台都消费货真价实的 tarball正是为了保证 CI 验证的就是用户会装到的东西。相关资源修复计划全文sdk/js-sdk/test/TARBALL_FRESHNESS_FIX_PLAN.md重打包与消费者管理脚本sdk/js-sdk/test/scripts/rebuild_sdk_and_pack.sh当前存在性检查的缺陷实现sdk/js-sdk/test/browser-next/scripts/run.mjs现有缓解脚本将被方案取代sdk/js-sdk/test/browser-next/refresh-sdk.sh触发缺陷的mtcoop单元定义sdk/js-sdk/test/browser-next/run-tests.sh多线程阈值判定逻辑sdk/js-sdk/test/browser-next/app/encrypt/page.jsx【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表