如何在Firebase Functions的Express中结合babel-watch使用webpack-hot-server-middleware
先直接回应你的两个核心问题:
- 开发环境下完全可以结合
webpack-hot-server-middleware与functions.https.onRequest(app),但需要调整代码结构和构建流程,让Firebase Functions能加载带热重载的Express应用。 firebase serve --only functions,hosting是正确的命令,但需要配合实时构建的流程,才能让热重载真正生效。
下面是具体的调整方案:
1. 修正Webpack Server配置的入口
你的webpack/server.js当前入口指向server/render.js,但实际的Express应用逻辑在server/index.js,需要把入口改成它,这样Webpack打包后生成的functions/index.js才会包含完整的Express配置和Firebase触发器导出:
// webpack/server.js const path = require("path"); module.exports = { name: "server", target: "node", entry: [path.resolve(__dirname, "../server/index.js")], // 改为server/index.js output: { filename: "index.js", path: path.resolve(__dirname, "../functions"), libraryTarget: "commonjs2" }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } ] }, // 开发环境启用source-map方便调试 devtool: "source-map" };
2. 调整Express应用的Firebase依赖引入
在server/index.js里,你直接使用了functions但没有引入,需要补充Firebase Functions的导入,并且要区分开发和生产环境(避免本地运行时找不到Firebase Functions环境):
// server/index.js import express from "express"; import webpack from "webpack"; import webpackDevMiddleware from "webpack-dev-middleware"; import webpackHotServerMiddleware from "webpack-hot-server-middleware"; import clientConfig from "../webpack/client"; import serverConfig from "../webpack/server"; // 仅在Firebase Functions环境或开发时引入functions let functions; try { functions = require("firebase-functions"); } catch (e) { // 本地直接运行时mock一个空的functions对象,避免报错 functions = { https: { onRequest: (app) => app } }; } const app = express(); const compiler = webpack([clientConfig, serverConfig]); // 仅在开发环境启用热重载中间件 if (process.env.NODE_ENV === "development") { app.use(webpackDevMiddleware(compiler, { publicPath: clientConfig.output.publicPath, stats: "minimal" })); app.use(webpackHotServerMiddleware(compiler)); } else { // 生产环境直接使用打包后的静态资源 app.use(express.static("build")); } export const firebaseTrigger = functions.https.onRequest(app);
3. 配置开发时的实时构建与运行
现在需要让Webpack在开发时实时打包server代码到functions目录,同时运行firebase serve。可以用concurrently来并行运行两个命令(先安装它:npm install --save-dev concurrently):
更新package.json的scripts:
{ "scripts": { "dev:build": "webpack --watch --config webpack/server.js --mode development", "dev:serve": "firebase serve --only functions,hosting", "dev": "concurrently \"npm run dev:build\" \"npm run dev:serve\"" } }
这样运行npm run dev时,Webpack会监听server代码变化,实时打包到functions/index.js,同时Firebase serve会加载最新的函数代码,结合webpack-hot-server-middleware实现React SSR的热重载。
4. 关于babel-watch的替代说明
其实在这个流程里,Webpack已经通过babel-loader处理了代码编译,再加上Webpack的watch模式,就不需要单独用babel-watch了。如果还是想用babel-watch直接运行Express(不通过Firebase serve),可以单独加一个脚本用于快速本地调试:
{ "scripts": { "dev:local": "NODE_ENV=development babel-watch server/local-server.js" } }
然后创建server/local-server.js,直接启动Express而不绑定Firebase Functions:
import app from "./index"; app.listen(3000, () => { console.log("Local SSR server running on http://localhost:3000"); });
这样你可以选择两种开发方式:
- 用
npm run dev模拟真实的Firebase环境 - 用
npm run dev:local快速本地调试Express
总结
firebase serve --only functions,hosting是正确的选择,能模拟生产环境的Hosting和Functions联动- 调整Webpack配置和代码结构后,完全可以在开发环境让
webpack-hot-server-middleware和Firebase Functions的HTTP触发器配合工作 - 通过并行运行Webpack watch和Firebase serve,实现代码修改后的实时重载
内容的提问来源于stack exchange,提问作者nakamura

