AWS Lambda中Puppeteer触发__dirname未定义ES模块错误排查
AWS Lambda中Node.js 20 + puppeteer-core 22.3.0的__dirname未定义错误排查与解决
问题场景
基于Node.js 20x版本,在AWS Lambda中使用puppeteer-core 22.3.0编写PDF生成代码,已通过fileURLToPath手动定义__dirname,但仍触发ReferenceError: __dirname is not defined in ES module scope错误,错误溯源至yargs模块。
代码示例
import * as fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import puppeteer from 'puppeteer-core'; const __filename = fileURLToPath(import.meta.url); // 获取文件的解析路径 const __dirname = path.dirname(__filename); // 获取目录名 export const handler = async (event) => { console.log(__dirname); console.log("Received event: " + JSON.stringify(event, null, 2)); const htmlContent = event.htmlContent; console.log("event", event); console.log("htmlContent", htmlContent); const pdfFileName = generatePDFFileName(); try { const browser = await puppeteer.launch(); const page = await browser.newPage(); await browser.close(); } catch (error) { console.error('Error generating PDF:', error); throw new Error('Error generating PDF'); } };
错误信息
ReferenceError: __dirname is not defined in ES module scope at node_modules/yargs/build/index.cjs (/node_modules/yargs/build/index.cjs:1:61388) at __require2 (file:///var/task/generatePdf.mjs:20:50) at <anonymous> (/node_modules/yargs/yargs.mjs:3:17) at ModuleJob.run (node:internal/modules/esm/module_job:218:25) at async ModuleLoader.import (node:internal/modules/esm/loader:329:24) at async _tryAwaitImport (file:///var/runtime/index.mjs:1008:16) at async _tryRequire (file:///var/runtime/index.mjs:1057:86) at async _loadUserApp (file:///var/runtime/index.mjs:1081:16) at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21) at async start (file:///var/runtime/index.mjs:1282:23)
原因分析
你手动定义的__dirname本身没有问题,错误根源在于yargs的CommonJS(CJS)版本代码在ES模块环境中被加载:
- 你的代码使用ES模块语法(
import),且文件为.mjs或package.json中设置了"type": "module",此时Node.js以ES模块模式运行。 - puppeteer-core依赖的yargs模块内部仍使用CJS语法,直接引用了
__dirname变量,但ES模块环境不会自动注入__dirname、__filename这类CJS专属变量,因此触发报错。 - 另外,你当前的
puppeteer.launch()未指定executablePath,在Lambda环境中无法找到无头Chrome,可能触发puppeteer内部调用yargs的命令行逻辑,进一步触发该错误。
解决方案
方案一:切换为CommonJS模块
将代码转为CJS格式,避免ES模块与CJS依赖的兼容性问题:
- 将Lambda入口文件扩展名从
.mjs改为.js(或删除package.json中的"type": "module")。 - 修改代码为CJS语法:
const fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer-core'); // CJS环境中__dirname自动存在,无需手动定义 exports.handler = async (event) => { console.log(__dirname); console.log("Received event: " + JSON.stringify(event, null, 2)); const htmlContent = event.htmlContent; console.log("event", event); console.log("htmlContent", htmlContent); const pdfFileName = generatePDFFileName(); try { const browser = await puppeteer.launch({ // 必须指定Lambda环境下的Chrome可执行路径,需配合chrome-aws-lambda包 executablePath: await require('chrome-aws-lambda').executablePath, args: require('chrome-aws-lambda').args, headless: require('chrome-aws-lambda').headless, }); const page = await browser.newPage(); // 此处添加生成PDF的逻辑,例如: // await page.setContent(htmlContent); // const pdfBuffer = await page.pdf({ format: 'A4' }); await browser.close(); return { statusCode: 200, body: 'PDF generated successfully' }; } catch (error) { console.error('Error generating PDF:', error); throw new Error('Error generating PDF'); } };
- 安装依赖:
npm install puppeteer-core chrome-aws-lambda
方案二:在ES模块环境中兼容yargs
如果坚持使用ES模块,可通过以下方式修复:
- 确保使用支持ES模块的yargs版本(v17+已支持ESM),重新安装依赖:
npm install yargs@latest - 在Lambda中正确配置puppeteer-core的启动参数,避免触发yargs的命令行逻辑:
import puppeteer from 'puppeteer-core'; import chrome from 'chrome-aws-lambda'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export const handler = async (event) => { try { const browser = await puppeteer.launch({ executablePath: await chrome.executablePath, args: chrome.args, headless: chrome.headless, }); const page = await browser.newPage(); await page.setContent(event.htmlContent); const pdf = await page.pdf({ format: 'A4' }); await browser.close(); return { statusCode: 200, body: pdf.toString('base64'), isBase64Encoded: true }; } catch (error) { console.error('Error generating PDF:', error); throw new Error('Error generating PDF'); } };
内容的提问来源于stack exchange,提问作者Mohit
相关产品推荐
相关产品推荐

