You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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依赖的兼容性问题:

  1. 将Lambda入口文件扩展名从.mjs改为.js(或删除package.json中的"type": "module")。
  2. 修改代码为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');
    }
};
  1. 安装依赖:npm install puppeteer-core chrome-aws-lambda

方案二:在ES模块环境中兼容yargs

如果坚持使用ES模块,可通过以下方式修复:

  1. 确保使用支持ES模块的yargs版本(v17+已支持ESM),重新安装依赖:npm install yargs@latest
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:57:11