Jack Joseph
Jack Joseph

Reputation: 129

Hosting a MERN application with Vercel in 2021 (without Next.js)

I've been using Vercel to host several React web applications and it's been great! Recently, I upgraded an existing project with a backend (Express.js and MongoDB Atlas) and I'd like to host it there as well.

On my machine, the MongoDB server and all the CRUD routes are running smoothly on localhost:5000, but I'd like to know how to add this to the Vercel deployment. Vercel's documentation focuses on serverless deployment, and while I don't mind rewriting my backend if I have to, I'm wondering if there's an easier solution for adding a server/database.

The MERN stack is still relatively popular so I imagine a lot of developers have found a way to host this kind of project. If anyone can help, I would really appreciate it!

Upvotes: 3

Views: 8884

Answers (3)

Marcia Moss
Marcia Moss

Reputation: 225

This repo is setup for MERN stack vercel deployment. I was able to adapt a MERN app and successfully deploy by forking this repo https://github.com/hack4impact-uiuc/mern-template/tree/main/client/src and updating.

Upvotes: 0

hello world
hello world

Reputation: 1

make sure you have the following in your backend app.js or server.js for the frontend to load on vercelapp/

app.use(express.static(path.join(__dirname, "../frontend/build")));

app.get("*", function(_, res) {
    res.sendFile(
        path.join(__dirname, "../frontend/build/index.html"),
        function (err) {
            if(err) {
                res.status(500).send(err)
            }
        }
    )
})

Since we are making a rewrite rule: /(.*) vercel will pass all requests through the backend server.js file This snippet will ensure that it sends the build/index.html

Sorry for bad english!

Upvotes: 0

MrJadeja
MrJadeja

Reputation: 451

according to your comment your file structure should be look like this

// + refer as close folder
// - refer as open folder
// > refer as file

main

  - backend
    + models
    + routes
    > package.json
    > package-lock.json
    > server.js

  - frontend
    + public
    - src
      + pages
      + components
    > package.json
    > package-lock.json

step1 - edit frontend package.json
add homepage

{
  // initially add link whatever you suppose to be link of your site
  // then after deploying to vercel, you get the exact link
  // then replace it with vercel link in "homepage" key

  "homepage": "https://awesome-app.vercel.app",
  "name": "awesome-app",
  "version": "1.0.0,
  "private": true,
  ...rest of your frontend package.json file
}

step2 - add basename

// you wrapped your app with either BrowserRouter or HashRouter
// add basename prop so it refer to your package.json homepage
// if your route are '/awesome-route' then is converted to
// https://awesome-app.vercel.app/awesome-route

<BrowserRouter basename='/'>    // or HashRouter
  <Switch>
    ...your routes
  </Switch>
</BrowserRouter>

step3 - build your react

you have to build your frontend everytime before deployment if and only if your change your frontend code

then your frontend should look like below

  - frontend
    + build    // build folder at root of your frontend
    + public
    - src
      + pages
      + components
    > package.json
    > package-lock.json

step4 - change your server.js file
should look like this

// i use "dotenv" package
// in your case must be located at "main > backend > .env"
// see the final file structure at bottom if you don't understand

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config({path: __dirname+'/.env'});
}

const express = require('express');
const mongoose = require('mongoose');
const path = require('path');

const app = express();
app.use(express.json());

const port = process.env.PORT || 5000;

mongoose.connect(process.env.mongoURI, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useCreateIndex: true,
  useFindAndModify: false,

  // remove poolSize or set according to your need
  // read docs before setting poolSize
  // default to 5
  poolSize: 1
})
  .then(() => {
    app.listen(port);
  })

// all your routes should go here
app.use('/some-route', require(path.join(__dirname, 'api', 'routes', 'route.js'));

// static files (build of your frontend)
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../frontend', 'build')));
  app.get('/*', (req, res) => {
    res.sendFile(path.join(__dirname, '../frontend', 'build', 'index.html'));
  })
}

step5 - add vercel.json at root level of your repository i.e., in your case main directory

{
  "version": 2,
  "builds": [
    {
      "src": "./backend/server.js",  // path to your server.js file
      "use": "@vercel/node"
    },
    {
      "src": "./frontend/build",    // path to your build folder
      "use": "@vercel/static"
    }
  ],

  // rewrites any request to api call with server.js
  // now your "app.use('/some-route')" would work as normal as localhost
  // no need to change your codes to serverless way

  // also remember here "/(.*)" is not regular js regex
  // it follows path-to-regex
  // playground link: https://regexr.com

  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/backend/server.js"
    }
  ]
}

finally your file structure look like this

// + refer as close folder
// - refer as open folder
// > refer as file

main

  - backend
    + models
    - routes
      > route.js
    > package.json
    > package-lock.json
    > .env
    > server.js

  - frontend
    - build
      + static
      > manifest.json
      > index.html
    + public
    + src
    > package.json
    > package-lock.json

  > vercel.json   // in your main directory's root

the disadvantage of this method is that your have to build your frontend every time you push your repo to github

remember to build your frontend before you push your repo to github if and only if you change your frontend code

also remember to replace your homepage url in your frontend package.json file after deployment with vercel provided url or your custom domain url

Happy Coding :)

Upvotes: 8

Related Questions