pkg默认仅打包require/import显式声明的模块,动态require、fs读取的JSON、child_process调用的二进制等均不会被自动识别,导致运行时Cannot find module或spawn ENOENT。

pkg打包时依赖没进可执行文件?先查detect逻辑
pkg默认只打包require或import显式声明的模块,动态require('some-' + name)、fs.readFileSync读取的JSON、甚至child_process.exec调用的本地二进制,都不会被自动识别。这导致运行时报Error: Cannot find module或spawn ENOENT。
验证方式:在lib/detector.ts第42行detect方法打个断点,运行pkg --debug examples/express/index.js,观察detected数组是否包含你预期的模块名。常见漏包场景:
-
dotenv加载.env文件——需手动加--assets .env -
sqlite3或node-sqlite3的预编译二进制——必须用--targets指定平台并确保构建环境一致 - 通过
__dirname拼接路径的模板文件(如path.join(__dirname, 'views', '*.html'))——得用--assets views/**/*
npm audit跑不出漏洞?因为pkg不等于npm install
npm audit检查的是node_modules目录下已安装的包,而pkg打包后运行时根本不用node_modules。所以你在开发机上npm audit --audit-level high显示“0 vulnerabilities”,不代表打包后的可执行文件安全。
真正要审计的是pkg最终打包进二进制的代码片段。实操建议:
- 在打包前执行
npm ls --prod --depth=10 > deps-tree.txt,人工确认高危包(如event-stream、lodash旧版)是否在依赖树里 - 用
pkg --debug输出的resolved列表,对照npm show 包名 versions --json查对应版本是否有CVE记录 - 对
node_modules做快照:tar -czf nm-before-pkg.tgz node_modules,打包后再解压比对实际打进二进制的文件
VSCode调试pkg时看不到真实错误堆栈?关掉sourceMaps反而更准
启用sourceMaps后,VSCode常把错误定位到lib-es5/bin.js的某一行,但那只是pkg CLI的包装层,不是你业务代码的真实位置。尤其当错误发生在打包后的运行时(比如require找不到模块),堆栈会失真。
ZenHeart zenlink 与 zenlink-mcp 为 OpenClaw,涵盖安装、MCP 注册、钩子接线、入站轮询及升级维护。
更有效的调试路径:
- 去掉
launch.json里的"sourceMaps": true和"outFiles",直接让VSCode停在原始TS文件(如lib/bin.ts) - 在
lib/packer.ts第89行pack方法里加console.log(options),确认options.assets、options.targets等关键参数是否符合预期 - 用
DEBUG=pkg:* pkg examples/express/index.js捕获完整日志,重点看[pkg] detected 12 modules和[pkg] packing to ...两段
金融/政企项目别信pkg --public,它不防供应链攻击
--public只是把源码从二进制里剥离,防止别人反编译看到你的业务逻辑,但它完全不校验依赖来源。一个被投毒的lodash或axios照样会打进可执行文件。
生产环境必须叠加动作:
- 锁定所有依赖精确版本:
"lodash": "4.17.21",禁用^和~ - 用
npx npm-force-resolutions强制覆盖间接依赖版本 - 在CI流程里加一步:
pkg --output /dev/null examples/express/index.js && echo "pack test passed",确保每次打包都触发完整依赖解析
真正麻烦的不是打包失败,而是打包成功却静默带入了恶意模块——这种问题在调试器里根本不会报错,只能靠构建时的依赖树快照和人工交叉核对。

















