Wednesday 17 May 2017

rendering react app on server

I'm trying to render my react website on the server but I think I am missing a step as when I use this as the links that get pulled in through ${content} don't work.

ReactDOMServer.renderToString(ComponentFactory()) The links that are in the layout don't work.

I have a server.js file which creates my node server using express:

const express = require('express');
const morgan = require('morgan');
const path = require('path');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
import { ServerRouter, createServerRenderContext, Router, RouterContext, match} from 'react-router';
import routes from './app/routes';
const util = require('util');
import {AppRoot} from './app/app-root';

const app = express();

// Serve static assets
app.use('/dist', (req, res, next) => {
  var result = req.url.match(/^\/js\/(maps|src)\/.+\.js$/)
  if (result) {
    return res.status(403).end('403 Forbidden')
  }
  next()
});
app.use('/dist', express.static(path.resolve(__dirname, '..', 'dist')));

app.set('port', (process.env.PORT || 3010));

app.get('*', function(req, res){
  match({routes: routes, location: req.url}, function(error, redirectLocation, renderProps) {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      var ComponentFactory = React.createFactory(AppRoot);
      var content = ReactDOMServer.renderToString(ComponentFactory());
      console.log(content);

      var metaDetails = {
        title: 'the title of the page is ' + req.url,
        description: 'the description of the page ' + req.url
      }

      res.send(renderPage(metaDetails, content));
    } else {
      res.status(404).send('Not found')
    }
  });
  res.end();
});

app.listen(app.get('port'), function() {
  console.log('Server started: http://localhost:' + app.get('port') + '/');
});


function renderPage(meta, content) {
  return `
    <!DOCTYPE html>
    <html>
      <head>
        <title>${meta.title}</title>
        <link rel="stylesheet" href="./dist/index-9d802856d32ae7a8b9e0b492d8b08022.css" />
        <meta charset="utf-8">
        <meta name="description" content="${meta.description}">
        <meta name="viewport" content="width=device-width">
        <link rel="icon" type="image/png" href="http://fountainjs.io/assets/imgs/fountain.png" />
      </head>

      <body>
        ${content}
        <div id="root"></div>
        <script type="text/javascript" src="./dist/vendor-a3ddf2ebae0065c48fcb.js"></script>
        <script type="text/javascript" src="./dist/app-a3ddf2ebae0065c48fcb.js"></script>
      </body>
    </html>
  `;
}

AppRoot is the layout of my app which looks like:

import React, {Component} from 'react';
import {Link} from 'react-router';
import PropTypes from 'prop-types';

export class AppRoot extends Component {
  render() {
    return (
      <div>
        <h2>React Universal App</h2>
        <Link to="/"> Home </Link>
        <Link to="/about"> List </Link>
        {this.props.children}
      </div>
    );
  }
}

AppRoot.propTypes = {
  children: PropTypes.object
};

This is my entry point:

import 'babel-polyfill';

import React from 'react';
import {Router, browserHistory} from 'react-router';
import ReactDOM from 'react-dom';
import routes from './app/routes';

import './index.scss';

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

My routes look like this:

import React from 'react';
import {Route, IndexRoute} from 'react-router';
import {Main} from './main';
import {About} from './about';

const data = [
  {id: 1, property: Main, link: '/'},
  {id: 2, property: About, link: '/login'},
  {id: 3, property: About, link: '/About'}
];

const routes = (
  <Route path="/">
    <IndexRoute component={Main}/>
    {data.map(page => {
      return <Route path={page.link} component={page.property} key={page.id}/>;
    })};
  </Route>
);

export default routes;


via saunders

No comments:

Post a Comment