NextJS 13.4.4部署至Vercel后Puppeteer无法运行求助
问题描述
我在NextJS API路由中用Puppeteer把动态HTML转成PDF,再通过邮件发送。本地开发完全正常,但部署到Vercel后调用API时出现以下错误:
- info Loaded env from /var/task/.env
- error Error: Could not find Chrome (ver. 113.0.5672.63). This can occur if either
- you did not perform an installation before running the script (e.g.
npm install) or- your cache path is incorrectly configured (which is: /home/sbx_user1051/.cache/puppeteer).
For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
at ChromeLauncher.resolveExecutablePath (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:300:27)
at ChromeLauncher.executablePath (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:181:25)
at ChromeLauncher.computeLaunchArguments (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:97:37)
at async ChromeLauncher.launch (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:83:28)
at async POST (/var/task/.next/server/app/api/p2/route.js:201:21)
at async /var/task/.next/server/chunks/625.js:2905:37
我试过Puppeteer文档里的配置文件,但都没用,我的代码如下:
import { NextResponse } from "next/server"; const puppeteer = require("puppeteer"); import mustache from "mustache"; const fs = require("fs"); const nodemailer = require("nodemailer"); export async function POST(request: Request) { const data = { nombre: "Vanessa", precio: 100, acciones: 12, }; const user = await request.json(); const browser = await puppeteer.launch({ headless: "new", args: ["--no-sandbox"], product: "firefox", }); const page = await browser.newPage(); const html = fs.readFileSync("src/app/api/p2/template.html", "utf8"); const filledHtml = mustache.render(html, data); await page.setContent(filledHtml, { waitUntil: "domcontentloaded" }); await page.emulateMediaType("screen"); const pdf = await page.pdf({ format: "A4", printBackground: true, margin: { top: "20px", bottom: "40px", left: "20px", right: "20px", }, path: "result.pdf", }); await browser.close(); console.log("Se genero el pdf"); let transporter = nodemailer.createTransport({ host: "m40.siteground.biz", port: 465, secure: true, // upgrade later with STARTTLS auth: { user: someuser, pass: somepass, }, }); let mailOptions = { from: someemail, to: someotheremail, subject: "Sending Email using Node.js", html: "<h1>Welcome</h1><p>That was easy!</p>", attachments: [ { filename: "result.pdf", path: "result.pdf", contentType: "application/pdf", }, ], }; transporter.sendMail(mailOptions, function (error: any, info: any) { if (error) { console.log(error); } else { console.log("Email sent: " + info.response); } }); return NextResponse.json("Se genero el pdf"); }
解决方案
Vercel的Serverless函数环境没有预装Chrome/Firefox,直接用puppeteer包会因为找不到浏览器二进制文件报错。下面是具体解决步骤:
步骤1:替换依赖
卸载原puppeteer,安装适配Serverless环境的包:
npm uninstall puppeteer npm install puppeteer-core chrome-aws-lambda
步骤2:修改API代码
调整浏览器启动逻辑,用内存处理PDF避免文件系统限制,同时用环境变量存敏感信息:
import { NextResponse } from "next/server"; import puppeteer from "puppeteer-core"; import mustache from "mustache"; import fs from "fs/promises"; import path from "path"; import nodemailer from "nodemailer"; export async function POST(request: Request) { const data = { nombre: "Vanessa", precio: 100, acciones: 12, }; const user = await request.json(); // 用chrome-aws-lambda获取适配Vercel的浏览器配置 const chrome = require("chrome-aws-lambda"); const browser = await puppeteer.launch({ args: chrome.args, executablePath: await chrome.executablePath, headless: chrome.headless, ignoreHTTPSErrors: true, }); const page = await browser.newPage(); // 确保模板路径在生产环境正确 const templatePath = path.resolve(process.cwd(), "src/app/api/p2/template.html"); const html = await fs.readFile(templatePath, "utf8"); const filledHtml = mustache.render(html, data); await page.setContent(filledHtml, { waitUntil: "domcontentloaded" }); await page.emulateMediaType("screen"); // 直接生成PDF Buffer,不写入本地文件 const pdfBuffer = await page.pdf({ format: "A4", printBackground: true, margin: { top: "20px", bottom: "40px", left: "20px", right: "20px", }, }); await browser.close(); console.log("PDF生成成功"); // 邮件发送逻辑,用Buffer作为附件 let transporter = nodemailer.createTransport({ host: "m40.siteground.biz", port: 465, secure: true, auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASS, }, }); let mailOptions = { from: process.env.EMAIL_FROM, to: process.env.EMAIL_TO, subject: "PDF已生成", html: "<h1>您好</h1><p>附件是生成的PDF文件</p>", attachments: [ { filename: "result.pdf", content: pdfBuffer, contentType: "application/pdf", }, ], }; try { await transporter.sendMail(mailOptions); console.log("邮件发送成功"); return NextResponse.json({ message: "PDF生成并发送成功" }); } catch (error) { console.error("邮件发送失败", error); return NextResponse.json({ error: "操作失败" }, { status: 500 }); } }
步骤3:配置环境变量
在Vercel控制台添加以下环境变量:
EMAIL_USER: 邮箱账号EMAIL_PASS: 邮箱授权码/密码EMAIL_FROM: 发件人邮箱EMAIL_TO: 收件人邮箱
关键说明
- chrome-aws-lambda:自动适配Vercel环境,提供预编译的Chrome二进制文件,不用手动配置路径。
- 内存处理PDF:Vercel临时文件系统有读写限制,直接用Buffer传递附件更可靠。
- 异步文件读取:用
fs/promises的异步方法,符合NextJS API的异步逻辑,避免阻塞。 - 环境变量存敏感信息:不要硬编码账号密码,用Vercel环境变量管理更安全。
内容的提问来源于stack exchange,提问作者Vanesa
相关产品推荐
相关产品推荐

