0

I trying deploy my MERN app to heroku.

After build success on heroku doesn't see a API routes:

Steps: On localhost I run concurrently node server and client (create-react-app). Server on port 5000 and client on port 3000. After this I fetch from API routes /hotels Array with items and connect it to Redux store and display it.

Properly behavior:

Localhost: works fine

Heroku: broken (didn't connect with API)

This is my server.js file:

const express = require('express');
const path = require('path');
const app = express();
const http = require('http');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');
const passport = require('passport');
const morgan = require('morgan');
const keys = require('./API/config/keys');

//######### MODELS #########
require('./API/models/Users');

//######### SERVICES #########
require('./API/services/passport');

//######### MONGODB CONNECT #########
mongoose.connect(MONGO_CONNECT);

//######### ROUTES #########
const hotelsRoutes = require('./API/routes/hotels');
const countRoutes = require('./API/routes/count');
const topRoutes = require('./API/routes/top');

// Use routes
app.use('/hotels', hotelsRoutes);
app.use('/count', countRoutes);
app.use('/top', topRoutes);

app.use(morgan('dev'));
app.use('/uploads', express.static('uploads'));
app.use(bodyParser.urlencoded({extended: false}));

app.use(bodyParser.json());
app.use(
  cookieSession({
      maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
      keys: [keys.cookieKey]
  })
);

app.use(passport.initialize());
app.use(passport.session());

require('./API/routes/authRoutes')(app);

app.use(express.static('client/build'));

app.get('*', (req, res) => {
   res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});

const port = process.env.PORT || 5000;
const server = http.createServer(app);

server.listen(port);

Package.json (server):

{
  "name": "root-react-hotel-app",
  "version": "0.1.0",
  "main": "server.js",
  "scripts": {
    "client": "cd client && yarn start",
    "start": "node server.js",
    "start-api": "nodemon server.js",
    "dev": "concurrently \"yarn start-api\" \"yarn client\"",
    "build": "cd client && npm install && yarn build"
  },
  "devDependencies": {
    //
  },
  "dependencies": {
    //
  }
}

Package.json (client):

{
  "name": "client-react-hotel-app",
  "version": "0.1.0",
  "private": true,
  "proxy": {
    "/auth/google": {
      "target": "http://localhost:5000"
    },
    "/api/*": {
      "target": "http://localhost:5000"
    },
    "/*": {
      "target": "http://localhost:5000"
    }
  },
  "dependencies": {
    // Here are dependencies
  },
  "scripts": {
    "build-css": "node-sass-chokidar src/ -o src/",
    "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
    "start-js": "react-scripts start",
    "start": "npm-run-all -p watch-css start-js",
    "build-js": "react-scripts build",
    "build": "npm-run-all build-css build-js",
    "eject": "react-scripts eject",
    "compile:sass": "node-sass src/css/styles.scss src/css/styles.css -w",
    "generate:doc": "sassdoc src/css/abstracts/_mixins.scss",
    "test": "cross-env NODE_ENV=test jest --config=jest.config.json",
    "test-coverage": "cross-env NODE_ENV=test jest --coverage --config=jest.config.json",
    "test-ci": "cross-env NODE_ENV=test jest --config=jest.config.json --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
  },
  "devDependencies": {
     // Here are devDependencies
  }
}

Also trying with static.json file and Procfile:

{
  "root": "client/build/",
  "setupFiles": [
    "<rootDir>/client/src/setupTests.js"
  ]
}

Anyone can help?

1

1 Answer 1

1

Since your express server is serving both your react bundle and your api routes, in:

app.get('*', (req, res) => {
   res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});

You need to protect your api routes in the 'app.get' when deploying to heroku (production mode). You can use a simple regex in order to serve all routes to your react bundle except '/api' (or whatever your api endpoint looks like, /API in your case above). It works running locally because you are running your api and react app on separate ports, not the same server.

Usually something like:

if (process.env.NODE_ENV === 'production') {
      app.get(/^\/(?!api).*/, (req, res) => { // don't serve react app to api routes
        res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
      });
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.