pkg构建场景下puppeteer page.evaluate传参异常问题咨询
- Node环境直接运行Puppeteer脚本时所有功能正常
- 用pkg对源码打包后,
page.evaluate、page.waitForFunction方法统一抛出SyntaxError: Unexpected identifier错误
触发错误的示例代码:
await page.evaluate((el) => {return el.value}, element)
pkg通过v8::ScriptCompiler编译脚本时不会保留函数的原始源码,传入page.evaluate的箭头函数(el) => {return el.value}会被转换为native code,Puppeteer无法将这类native code序列化后注入浏览器上下文执行,因此触发语法错误。
该问题对应Puppeteer官方issue「Cannot pkg puppeteer app due to ExecutionContext.js - SyntaxError: Unexpected identifier」,核心结论和上述排查结果一致。
已知修复方向是给page.evaluate传入字符串类型的执行逻辑而非函数,通过字符串拼接选择器的hack方案可实现基础功能,代码如下:
page.evaluate( `(() => { let els=document.querySelectorAll("${selector}"); let el = els[0]; return el.value; })();` );
但该方案需要同时兼容CSS选择器、XPath选择器场景,需要在字符串逻辑内写两套节点查询逻辑,代码冗余混乱。
尝试给字符串形式的执行逻辑传入外部ElementHandle参数时,浏览器上下文内拿到的参数始终为undefined,无效写法如下:
page.evaluate( `((el) => { return el.value; })();`, element );
参数为undefined的核心原因是:你在字符串逻辑外层手动包裹了立即执行函数(...)(),Puppeteer无法将后续传入的参数注入到你自己写的自执行函数作用域中。
去掉自执行包裹,直接将函数本身作为字符串传入,后续跟要传递的参数即可,Puppeteer会自动完成参数序列化(ElementHandle会被自动转换为页内对应的真实DOM节点),不管是CSS选择器还是XPath拿到的ElementHandle都支持,不需要在evaluate内部写节点查询逻辑:
// 箭头函数写法 await page.evaluate( `(el) => { return el.value }`, element )
如果要兼容更低版本的Puppeteer,可以用普通函数+arguments的写法,稳定性更高:
// 兼容写法 await page.evaluate( `function() { const el = arguments[0]; return el.value; }`, element )
page.waitForFunction的修复逻辑完全一致,将原本传入的函数替换为等价的字符串形式即可,不需要修改传参逻辑。
内容的提问来源于stack exchange,提问作者endeavour

