如何将自建React+Express项目部署到Heroku?
Hey there! Congrats on getting your React + Express setup working locally with webpack --watch—that's a solid start. Let's walk through how to get this deployed to Heroku step by step, since their platform has a few specific requirements you'll need to account for as a first-time full-stack deployer.
package.json for Heroku Compatibility Heroku relies on your package.json to know how to build and run your app. Here's what you need to adjust:
1.1 Update Scripts
Your local start script uses webpack --watch for development, but production doesn't need live reloading. Replace it with separate dev and production scripts:
"scripts": { "dev": "webpack --watch & node server.js", // Keep this for local development "build": "webpack --mode production", // Heroku will run this to build your React bundle "start": "node server.js" // Heroku uses this to start your Express server }
1.2 Specify Node.js Version
Add an engines field to avoid version mismatches between your local setup and Heroku:
"engines": { "node": ">=16.x", "npm": ">=8.x" }
Use the same Node/npm version you're running locally (check with node -v and npm -v).
1.3 Ensure Dependencies Are Correct
Make sure all build tools (like webpack, babel-loader, etc.) are in devDependencies—Heroku will install them during the build phase, then discard them to save space. If you run into build errors later, you can temporarily move them to dependencies, but devDependencies is the right place for tools only needed during development/build.
Heroku will run npm run build to generate your optimized React bundle (usually in a dist folder, depending on your webpack config). Your Express server needs to serve these static files and handle SPA routing:
2.1 Serve Static Files
Add this to your server file (e.g., server.js or server/index.js):
const path = require('path'); const express = require('express'); const app = express(); // Serve React's static files from the dist folder app.use(express.static(path.join(__dirname, 'dist'))); // If your server code is in a subfolder (like /server), use ../dist instead: // app.use(express.static(path.join(__dirname, '../dist')));
2.2 Handle SPA Routing
For single-page apps, any non-API request should return React's index.html to avoid 404s when users refresh:
// Place this AFTER all your API routes app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'dist', 'index.html')); // Adjust path if server is in a subfolder: path.join(__dirname, '../dist', 'index.html') });
2.3 Use Heroku's Dynamic Port
Heroku assigns a random port to your app via the PORT environment variable—never hardcode a port like 3000:
const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
webpack.config.js for Production Make sure your webpack config is set up to generate a production-ready bundle:
3.1 Set Output Path and Filenames
Ensure your build outputs to a consistent folder (like dist) with hashed filenames for caching:
const path = require('path'); module.exports = (env, argv) => { const isProduction = argv.mode === 'production'; return { entry: './src/index.js', // Your React entry point output: { path: path.resolve(__dirname, 'dist'), filename: isProduction ? '[name].[contenthash].js' : '[name].js', clean: true, // Empty the dist folder before each build }, // ... rest of your config }; };
3.2 Adjust Devtool and Plugins
- For production, use
devtool: 'source-map'(orfalseif you don't need source maps) instead of inline dev tools. - Use
MiniCssExtractPluginto extract CSS into separate files (instead ofstyle-loaderfor development):
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); // Inside your module.rules for CSS: { test: /\.css$/, use: [isProduction ? MiniCssExtractPlugin.loader : 'style-loader', 'css-loader'], } // Inside plugins array: plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' }), isProduction && new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }), ].filter(Boolean) // Only include the CSS plugin in production
Now you're ready to push your code live:
Initialize Git (if you haven't already):
git init git add . git commit -m "Prepare app for Heroku deployment"Install Heroku CLI (if you don't have it), then log in:
heroku loginCreate a Heroku app:
heroku create your-app-name # Replace with a unique name, or leave blank for a random oneDeploy your code:
git push heroku mainOpen your live app:
heroku open
- Build fails: Check Heroku's logs with
heroku logs --tailto see exactly what's breaking. Common fixes: missing dependencies, incorrect webpack config paths, or Node version mismatches. - 404 on page refresh: Double-check your SPA routing code in Express—make sure
app.get('*')is placed after all your API routes. - Static files not loading: Verify the path to your
distfolder in Express is correct (usepath.resolveto avoid relative path bugs).
内容的提问来源于stack exchange,提问作者JEEZSUSCRIZE

