I need to know the flow of this MERN app.

I am looking to get to know the flow of a MERN application. I want to know how everything is taking place; who is serving whom. How React and Express are connected to each other? Can anyone explain me like five, what happens, say, a request is made from the client. I need to know the whole process in between. Why did we use an ejs template here? Is this app Server Side Rendered or Client Side Rendered? I am using React and Redux on the frontend and Express and MongoDB on the backend. But I'm confused how's everything connected. Please shed some light as I'm really confused. Thanks.

Folder structure:

Screenshot 2020-06-12 12:33:24.png

webpack.config.js

/* eslint-disable */
var webpack = require("webpack")
var path = require("path")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = {
  mode: "development",
  devtool: "inline-source-map",
  entry: ["./client/index.js"],
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: { loader: "babel-loader" },
      },
      {
        test: /\.(scss|css)$/,
        use: [
          { loader: MiniCssExtractPlugin.loader },
          {
            loader: "css-loader",
          },
          { loader: "sass-loader" },
        ],
      },
      {
        test: /\.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: "file-loader",
            options: {},
          },
        ],
      },
    ],
  },
  resolve: {
    extensions: [".js", ".jsx"],
  },
  output: {
    filename: "bundle.js",
    path: __dirname + "/dist/bundle/",
    publicPath: "/static/",
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      "process.env": {
        NODE_ENV: JSON.stringify("development"),
      },
    }),
    new MiniCssExtractPlugin({
      filename: "bundle.css",
    }),
  ],
}

app.js

const createError = require("http-errors")
const express = require("express")
const bodyParser = require("body-parser")
const path = require("path")
const cookieParser = require("cookie-parser")
const logger = require("morgan")
const mongoose = require("mongoose")
const dotenv = require("dotenv")

const indexRouter = require("./routes/index")
const userRouter = require("./routes/users")

const app = express()

// view engine setup
app.set("views", path.join(__dirname, "views"))
app.set("view engine", "ejs")

app.use(logger("dev"))
app.use(express.json())
app.use(bodyParser.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, "public")))

if (process.env.NODE_ENV === "development") {
  const webpack = require("webpack")
  const webpackConfig = require("./webpack.config")
  const compiler = webpack(webpackConfig)

  app.use(
    require("webpack-dev-middleware")(compiler, {
      noInfo: true,
      publicPath: webpackConfig.output.publicPath,
    })
  )

  app.use(require("webpack-hot-middleware")(compiler))
}

mongoose.connect(
  "mongodb://localhost:27017/myApp",
  { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false },
  function (err) {
    if (err) {
      console.log("Not connected")
    } else {
      console.log("Connected successfully")
    }
  }
)

app.use("/api/v1/users", userRouter)
app.use("/*", indexRouter)

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404))
})

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message
  res.locals.error = req.app.get("env") === "development" ? err : {}

  // render the error page
  res.status(err.status || 500)
  res.render("error")
})

module.exports = app

client/index.js

import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
import { Provider } from "react-redux"
import store from "./store"

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
)

routes/index.js

var express = require("express")
var router = express.Router()

/* GET home page. */
router.get("/*", function (req, res, next) {
  res.render("index", { title: "My App" })
})

module.exports = router

views/index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel='stylesheet' href='/static/bundle.css' />
    <script src="https://kit.fontawesome.com/afb66cf461.js" crossorigin="anonymous"></script>
  </head>
  <body>
    <div id="root"></div>
    <script src="/static/bundle.js"></script>
  </body>
</html>

Learn Something New Everyday,
Connect With The Best Developers!

Sign Up Now!

& 500k+ others use Hashnode actively.

Comments (6)

Amit Chambial's photo

Here Webpack is used to build react jsx.

webpack.config.js

  • entryPoint: points to React index.js that resides in client/index.js
  • outputDir : /static/bundle.js( after the build is complete the bundle.js go in this folder

app.js

app.use("/api/v1/users", userRouter)

  • all the /api/v1/users request goes to userRouter

app.use("/*", indexRouter)

  • all the / request goes to index.js router which in return route it to index.ejs
  • in index.ejs react js bundle file is included , hence routing for /* will be handled by react routers
  • in index.ejs the react component will be rendered inside <div id="root"></div>

similar to create-react-app we have public/index.html there , here we have index.ejs

Show +3 replies
Dave Rodriguez's photo

Thank you so VERY much. I really appreciate your time and knowledge. Cheers.Amit Chambial