How can I have React routed UI on top of Express 4 code base?

88 views Asked by At

Basically I want to have a react app, but also this app's API calls have to be routed through a middleware so I need a backend code for this too in same app. I tried doing two ways:

  1. Created express backend with generator. Then added react code in public and added web pack and babel but when I enable routes in express for api, react stops rendering.

  2. Created express backend with generator. Added create-react-app in client folder and added proxy line to the express backend. Now it works and I'm able to calls the Middleware for processing apis. But the thing is both express server and client app run on different ports and I need them in same port.

How do I solve it? Using the Middleware to access services is mandatory, I can't directly just Ajax it from UI. It has to go through backend. And I used kraken generator for the node app.

1

There are 1 answers

1
Cisco On

Technically yes, but it's more hassle than what it's worth. Assuming you already have a fully configured webpack setup for React, you will need the following:

  1. webpack-dev-middleware
  2. webpack-hot-middleware

We need to configure Express to serve your React bundle in development. This app.js would only be for development purposes only. It should not be used for production.

With that said, you'll want something like the following:

const path = require('path')
const express = require('express')
const webpack = require('webpack')
const webpackConfig = require('./path/to/config')
const webpackHotMiddleware = require('webpack-hot-middleware')

const port = process.env.PORT || 3000
const app = express()
const compiler = webpack(webpackConfig)

// Configure webpack dev server and hot reload.
const devMiddleware = require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
  quiet: true
})

const hotMiddleware = webpackHotMiddleware(compiler)

// Force page reload when html-webpack-plugin template changes.
compiler.plugin('compilation', (compilation) => {
  compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
    hotMiddleware.publish({ action: 'reload' })
    cb()
  })
})

// Serve webpack bundle output
app.use(devMiddleware)

// Enable hot-reload and state-preserving.
// Compilation error display.
app.use(hotMiddleware)

// serve pure static assets
app.use('/some/path', express.static('/some/path'))

// The webpack dev server bundle is stored in memory,
// so we need to write its contents to the response body.
app.get('/', (req, res) => {
  res.write(
    devMiddleware.fileSystem.readFileSync(path.join(__dirname, 'dist/index.html'))
  )
  res.end()
})

// Redirect any invalid requests back to document root with a 404 status
app.all('*', (req, res) => { res.status(404).redirect('/') })

// We need to wait until bundle is valid in development
console.log('Waiting for webpack to finish...')
devMiddleware.waitUntilValid(startServer)

function startServer () {
  app.listen(port, () => {
    console.log(`http://localhost:${port}`)
  })
}

For production, this would be simplified to just:

const { join } = require('path')
const express = require('express')
const bodyParser = require('body-parser')

const port = process.env.PORT
const app = express()

// Wherever your webpack config builds the bundle
app.use(express.static(join(__dirname, '../dist')))

// Redirect any invalid requests back to document root with a 404 status
app.all('*', (req, res) => { res.status(404).redirect('/') })

app.listen(port, () => {
  console.info(`Server is running at ${port}`)
})