3

I have an app where I configured server side rendering. Everything is working nice and my component is rendered on the server. The problem is that I get my component rendered twice on the screen. One comes from <div id="content"><%- content %></div>that I am using for server rendering and one comes from <script src="http://localhost:3001/bundle.js"></script>. I use webpack to make two bundles for my server and client. Why is this happening and how can I fix this?

views/index.ejs

<body>
  <div id="app"></div>
  <div id="content"><%- content %></div>
  <script src="http://localhost:3001/bundle.js"></script>
</body>

index.js

app.use(Express.static(path.join(__dirname, '../', 'dist')))

app.use(serverRenderer)
app.get('*', (req: Object, res: Object) => {
  res.render('index', {content: req.body})
})

serverRender

import React from 'react'
import ReactDOM from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import routes from '../client/routes.js'

async function render (component) {
  const content = ReactDOM.renderToString(component)
  return content
}

async function getMatchParams (routes, currentUrl) {
  return new Promise((resolve, reject) => {
    match({routes: routes, location: currentUrl}, (err, redirect, props) => {
      if (err) {
        return reject(err)
      }
      return resolve(props)
    })
  })
}

export default async(req, res, next) => {
  const renderProps = await getMatchParams(routes, req.url)
  if (renderProps) {
    const component = (
      <RouterContext {...renderProps} />
    )
    req.body = await render(component)
    next()
  }
}
Igor-Vuk
  • 3,551
  • 7
  • 30
  • 65

2 Answers2

1

Ok. I have found a problem. I was referring to the bundle and server rendered string with two separate <div>. Inside my app.js I was doing this

render(
    <Router history={browserHistory}>
      {routes}
    </Router>,
  document.getElementById('app')
)

Thats why I should have been sending the string to the template like this.

app.use(Express.static(path.join(__dirname, '../', 'dist')))

app.use(serverRenderer)
app.get('*', (req: Object, res: Object) => {
  res.render('index', {app: req.body})
})

And finally my views/index.js should look like this

<body>
  <div id="app"><%- app %></div>
  <script src="http://localhost:3001/bundle.js"></script>
</body>
Igor-Vuk
  • 3,551
  • 7
  • 30
  • 65
0

I also faced that problem and found a solution.

On package.json,

"start": "npm-run-all --parallel dev:*",

It will run webpack and node build/bundle.js. Then 2 things happened simultaneously, webpack build project, node build/bundle.js

After webpack built project, then node build/bundle.js runs again since bundle.js is changed.

So there was twice calls on both server and client side. I solved this problem very easily.

First run npm run build, then run node build/bunde.js . Then it will run everything once :)

Zhong Ri
  • 2,556
  • 1
  • 19
  • 23