punkbit
punkbit

Reputation: 7707

How to transpile all React ES6 Components for Server Side Rendering route match

I've been reading a lot of articles and research on React Server Side Rendering, using Webpack, Express, etc common setup. Most use React + ES6 for components, placing babel-register at the beginning of the express entry point, to allow sharing the React Routes written in ES6 between client and server. Others, run babe-node to solve this issue. Unfortunately babel-register or babel-node are not recommended for production use and it's obviously recommended compiling to a separate file for production.

// As an example, demonstrating that `production` should not
// require babe-register, but development
if (['staging', 'production'].indexOf(process.env.NODE_ENV) > -1) {
  require('./dist/server.prod.js')
} else {
  require('babel-register')
  require('./server.dev.js')
}

As far as I know and tested (unless I missed something on my setup), client side works fine (a single bundled js file with all the routes etc in it); While the server-side render fails because of syntax errors. The builder transpiles the express ES6 code (server) to ES5, but doesn't transpile all the routes components in advance has these are hit dynamically!

See the following example, for a project without Routes, where this is not an issue since the App component is imported in advance, so the build job transpiles it:

router.get('*', (req, res, next) => {
  const preloadedState = {'foobar': 1}
  const store = configureStore(preloadedState)
  const myAppHtml = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  )
  const finalState = store.getState()
  let html = htmlTemplateString.replace('<div id="app">', '<div id="app">' + myAppHtml)
  const preloadedStateScript = `<script>window.__PRELOADED_STATE__ = ${JSON.stringify(finalState).replace(/</g, '\\x3c')}</script>`
  html = html.replace('</head>', preloadedStateScript)
  res.send(html)
})

While, a dynamic route changes in the server, will import React ES6 components and cause syntax errors. For example:

router.get('*', (req, res) => {
  match({routes, location: req.url}, (error, redirectLocation, renderProps) => {
    const myAppHtml = renderToString(<RouterContext {...renderProps}/>);
    ...
  })
})

My question is about how to transpile all the React ES6 Components to avoid use of babel-register or babel-node in the production?

Webpack has a ExtractTextPlugin that is used to extract CSS from the output into individual files, is it possible to do the same for the Components?

Do we have to run babel to transpile all the React App directory structure into a new directory that'll be used just for Server side rendering in production?

These are some of the questions I didn't find any answer in most articles I found about React Server side rendering, when using Routes and Match routes.

Upvotes: 0

Views: 935

Answers (1)

Martin Skec
Martin Skec

Reputation: 128

You can transpile all files in build process and run server from transpiled files. You can use webpack for that.

Check how this starter project is doing it: https://github.com/ctrlplusb/react-universally

Upvotes: 0

Related Questions