Fetching from localhost server in Create React App during development vs fetching from deployment during production

Viewed 1351

This is a personal portfolio page that I'm implementing a contact form within, using nodemailer.

The nodemailer thing is all set from server side. I just need some advice on pointing the client post request to the right place in regards to development and deployment.

I figured as much for setting an environment variable for production vs development and hitting the fetch based upon that. Now I'm just wondering how to go about finding whatever I would put in the fetch for production.

would it be just pointing back into my own app: fetch(www.mydomain.com/send-email, data) ...

I'm in the Heroku docs trying to figure this out.

Basically, I have a huge blind spot which is hitting a server API from Create React App that isn't launched independently on localhost:3000. I have yet to hit a server route from my client that wasn't served locally on localhost. When I push this to Heroku, I need to have the right route or config, what I need is some advice on how to do this.

I understand proxying somewhat. Just wondering what the steps are to properly hit my server route from an client/server deployed on Heroku as opposed to localhost:3000 during deployment.

When I'm in development I pretty much always axios.post a server that I've spun up on localhost:3000, which I then hit with something like this coming from my client..

axios.post('localhost:3000/send-email', data)
      .then( () => {
        setSent(true) 
      })
      .then(() => {
        resetForm()
      })
      .catch((err)=> {
        console.log('Message not sent', err)
      })
  }

...which is then handled by an endpoint on the express server listening on localhost:3000, that looks somewhat like what I've pasted below.

const express = 
  require('express'), 
  bodyParser = require('body-parser'), 
  nodemailer = require('nodemailer'), 
  cors = require('cors'), path = require('path'), 
  port = process.env.PORT || 3000, publicPath = path.join(__dirname, '..', 'build');
require('dotenv').config();
const app = express();

app.use(cors());
app.use(express.static(publicPath));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('*', (req, res) => {
  res.sendFile(path.join(publicPath, 'index.html'));
});

app.post('/send-email', (req, res) => {
  console.log('request: ', req.body)
  let data = req.body;
  let transporter = nodemailer.createTransport({
    service: 'gmail',
    port: 465,
    auth: {
      user: process.env.EMAIL,
      pass: process.env.PASSWORD
    }
  });

  let mailOptions = {
    from: data.email,
    to: process.env.EMAIL,
    subject: `${data.subject}`,
    html: `<p>${data.name}</p>
            <p>${data.email}</p> 
            <p>${data.message}</p>`
  };

  transporter.sendMail(mailOptions,
  (err, res) => {
    if(err) {
      res.send(err)
    } else {
      res.send('Success')
    }
    transporter.close();
  });
})

app.listen(port, () => {
  console.log(`Server is up on port ${port}!`);
});

folder structure is like this:

main
 |-server
  |-server.js
 |-src
  |-components
    |-Contact.js
1 Answers

Use the process.env.NODE_ENV variable to differ the environments.

When you run npm start, it is always equal to 'development', when you run npm test it is always equal to 'test', and when you run npm run build to make a production bundle, it is always equal to 'production'. You cannot override NODE_ENV manually.

Therefore, you can create and export a function like

export function apiDomain() {
    const production = process.env.NODE_ENV === 'production'
    return production ? 'anotherDoman' : 'localhost:3000'
}

or maybe, depending on your requirements

export function apiDomain() {
    const { protocol, hostname, origin } = window.location
    return hostname === 'localhost' ? `${protocol}//${hostname}` : origin
}

For more details, take a look at https://create-react-app.dev/docs/adding-custom-environment-variables/

Related