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