Firebase Functions部署报错:ES模块与CommonJS语法冲突求助
问题:Firebase Functions部署Twilio+OpenAI WhatsApp应用时的模块语法冲突
问题描述
基于教程开发结合Twilio与OpenAI的WhatsApp聊天应用,核心功能通过Firebase Functions实现,部署时遭遇模块语法冲突:
- 保留
package.json中"type":"module"配置时,报错:
Error: Failed to load function definition from source: Failed to generate manifest from function source: ReferenceError: require is not defined in ES module scope, you can use import instead
- 移除
"type":"module"配置后,报错:
Error: Failed to load function definition from source: Failed to generate manifest from function source: SyntaxError: Cannot use import statement outside a module
尝试将OpenAI模块移至node_modules目录,问题未解决。
相关代码
const functions = require("firebase-functions"); import { Configuration, OpenAIApi } from "openai"; const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, }); const openAI = new OpenAIApi(configuration); export default async function handler(req, res) { const MessagingResponse = require('twilio').twiml.MessagingResponse; var messageResponse = new MessagingResponse(); const sentMessage = req.body.Body || ''; let replyToBeSent = ""; if (sentMessage.trim().length === 0) { replyToBeSent = "We could not get your message. Please try again"; } else { try { const completion = await openAI.createCompletion({ model: "text-davinci-003", // required prompt: req.body.Body, // completion based on this temperature: 0.6, n: 1, max_tokens: 50, // stop: "." }); replyToBeSent = removeIncompleteText(completion.data.choices[0].text) } catch (error) { if (error.response) { replyToBeSent = "There was an issue with the server" } else { // error getting response replyToBeSent = "An error occurred during your request."; } } } messageResponse.message(replyToBeSent); // send response res.writeHead(200, { 'Content-Type': 'text/xml' }); res.end(messageResponse.toString()); } // trims out the words/char that may be left hanging by chatgpt because the character(token) limit is reached for a response function removeIncompleteText(inputString) { const match = inputString.match(/\b\.\s\d+/g); const removeAfter = match ? inputString.slice(0, inputString.lastIndexOf(match[match.length - 1])) : inputString; return removeAfter }
package.json配置
{ "name": "appName", "version": "1.0.0", "description": "", "type": "module", "scripts": { "lint": "eslint .", "serve": "firebase emulators:start --only functions", "shell": "firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log", "test": "echo \"Error: no test specified\" && exit 1" }, "engines": { "node": "16" }, "main": "index.js", "dependencies": { "firebase-admin": "^11.5.0", "firebase-functions": "^4.2.0", "next": "^13.2.4", "openai": "^3.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "twilio": "^4.9.0" }, "devDependencies": { "eslint": "^8.15.0", "eslint-config-google": "^0.14.0", "firebase-functions-test": "^3.0.0" }, "private": true, "keywords": [], "author": "", "license": "ISC" }
解决方案
问题根源是代码混合使用了CommonJS(require)和ES模块(import/export)语法,Firebase Functions要求统一模块规范,以下是两种可行方案:
方案1:统一使用ES模块(保留"type":"module")
将所有require替换为import,并调整Firebase函数导出方式:
- 替换
const functions = require("firebase-functions");为:
import functions from "firebase-functions";
- 替换
const MessagingResponse = require('twilio').twiml.MessagingResponse;为:
import { twiml } from 'twilio'; const MessagingResponse = twiml.MessagingResponse;
- 将
export default async function handler(...)改为命名导出:
export const handler = functions.https.onRequest(async (req, res) => { ... })
修改后的完整代码:
import functions from "firebase-functions"; import { Configuration, OpenAIApi } from "openai"; import { twiml } from 'twilio'; const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, }); const openAI = new OpenAIApi(configuration); const MessagingResponse = twiml.MessagingResponse; export const handler = functions.https.onRequest(async (req, res) => { var messageResponse = new MessagingResponse(); const sentMessage = req.body.Body || ''; let replyToBeSent = ""; if (sentMessage.trim().length === 0) { replyToBeSent = "We could not get your message. Please try again"; } else { try { const completion = await openAI.createCompletion({ model: "text-davinci-003", prompt: req.body.Body, temperature: 0.6, n: 1, max_tokens: 50, }); replyToBeSent = removeIncompleteText(completion.data.choices[0].text) } catch (error) { if (error.response) { replyToBeSent = "There was an issue with the server" } else { replyToBeSent = "An error occurred during your request."; } } } messageResponse.message(replyToBeSent); res.writeHead(200, { 'Content-Type': 'text/xml' }); res.end(messageResponse.toString()); }); function removeIncompleteText(inputString) { const match = inputString.match(/\b\.\s\d+/g); const removeAfter = match ? inputString.slice(0, inputString.lastIndexOf(match[match.length - 1])) : inputString; return removeAfter; }
方案2:统一使用CommonJS(移除"type":"module")
将所有import/export替换为require和module.exports:
- 替换
import { Configuration, OpenAIApi } from "openai";为:
const { Configuration, OpenAIApi } = require("openai");
- 将
export default async function handler(...)改为:
exports.handler = functions.https.onRequest(async (req, res) => { ... });
额外注意事项
- 确保
package.json的main字段指向正确的入口文件(此处为index.js)。 - Firebase Functions Node.js 16支持两种模块规范,但必须统一,禁止混合使用。
- 无需手动移动node_modules中的模块,
npm install会自动处理依赖位置。
内容的提问来源于stack exchange,提问作者Ndheti
相关产品推荐
相关产品推荐

