在Heroku部署React应用时遇'Could not find a required file. Name: index.html'错误
解决Heroku部署React+Express应用时找不到index.html的问题
嘿,刚接触React和部署确实容易踩这些坑,别着急,咱们一步步把问题搞定!你遇到的核心问题是构建脚本的执行路径不对,再加上server.js里的静态文件配置有误,导致Heroku找不到index.html,生产环境也没法正确提供前端资源。
1. 先修正package.json的脚本配置
你的根目录package.json里的build脚本直接在根目录跑react-scripts build,但React项目的public和src都在client子文件夹里啊!根目录根本没有这些文件,难怪会报错找不到index.html。另外,Heroku需要明确你的Node和npm版本,得把版本信息放到engines字段里(你之前直接写在根节点是无效的)。
修正后的package.json关键部分:
"name": "mern-auth", "version": "1.0.0", "homepage": "./", "description": "Mern Auth Example", "main": "server.js", "engines": { "node": "v12.13.1", "npm": "6.13.4" }, "scripts": { "client-install": "npm install --prefix client", "build": "cd client && npm run build", // 进入client目录再执行构建 "start": "node server.js", "server": "nodemon server.js", "client": "npm start --prefix client", "dev": "concurrently \"npm run server\" \"npm run client\"", "heroku-postbuild": "npm run client-install && npm run build" // 让Heroku自动安装client依赖并构建 }
加个heroku-postbuild脚本很重要,这样Heroku部署时会自动安装client的依赖,不用手动处理。
2. 修复server.js的静态文件服务和路由 fallback
生产环境下,Express要提供的是React构建好的静态文件(也就是client/build里的内容),不是直接访问client/public。而且路由 fallback 要指向build文件夹里的index.html,不是public里的原始文件。另外,你之前漏了导入express,这会导致服务器启动失败哦!
修正后的server.js核心代码:
// 先补上express的导入! const express = require('express'); const mongoose = require("mongoose"); const bodyParser = require("body-parser"); const passport = require("passport"); const path = require('path'); const users = require("./routes/api/users"); const plaid = require("./routes/api/plaid"); const morgan = require("morgan"); const app = express(); // Bodyparser和日志中间件 app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(morgan("tiny")); // API接口 app.get("/api/message", async (req, res, next) => { try { res.status(201).json({ message: "HELLOOOOO FROM EXPRESS" }); } catch (err) { next(err); } }); // 生产环境静态文件配置 if (process.env.NODE_ENV === "production") { // 指向client/build文件夹 const buildPath = path.resolve(__dirname, 'client', 'build'); app.use(express.static(buildPath)); // 所有非API请求都返回React的index.html(解决单页应用路由问题) app.get('*', (req, res) => { res.sendFile(path.join(buildPath, 'index.html')); }); } // Passport配置 app.use(passport.initialize()); require("./config/passport")(passport); // 挂载API路由 app.use("/api/users", users); app.use("/api/plaid", plaid); // 连接MongoDB(放到服务器启动前) const db = require("./config/keys").mongoURI; mongoose.connect(db, { useNewUrlParser: true }) .then(() => console.log("MongoDB successfully connected")) .catch(err => console.log(err)); // 启动服务器 const port = process.env.PORT || 5000; app.listen(port, () => { console.log(`Server is up on port ${port}!`); });
3. 最后做个本地测试再部署
先在本地跑一遍生产环境流程:
- 运行
npm run build,看看client文件夹下有没有生成build文件夹 - 运行
npm start,访问http://localhost:5000,确认应用能正常加载 - 没问题的话,就可以推代码到Heroku了
这样调整后,Heroku就能正确构建前端资源,服务器也能正确提供静态文件,应该就能解决你的问题啦!
内容的提问来源于stack exchange,提问作者wharfchillin
相关产品推荐
相关产品推荐

