Closed That-David-Guy closed 8 years ago
Not sure about the ejs. But I managed to get it working without the use of ejs - I used react as templating engine. This needs 2 react renders on the server (one for the outer html template without the react handles and one for the app itself) and just one standard rendering on the client (for the app itself).
//package.json snippet
{ "dependencies": {
"react": "^0.13.3", //sorry, I have not upgraded yet
"react-helmet": "^1.1.5", //optional, just to get the title generated in static site for SEO
"react-router": "^1.0.0-rc1"}}
//index.js
var React = require('react');
var Router = require('react-router/lib/Router');
var Routes = require('./Routes');
//client code
if (typeof document !== 'undefined') {
var createBrowserHistory = require('history/lib/createBrowserHistory');
var history = createBrowserHistory();
//render app and attache to <div id="content"> in the HTML document
React.render(<Router history={history}>{Routes}</Router>, document.getElementById('content'));
}
//static site generator code
module.exports = function render(locals, callback) {
var Helmet = require('react-helmet');
var createMemoryHistory = require('history/lib/createMemoryHistory');
var Html = require('./Html.js');
var history = createMemoryHistory(locals.path);
//render app to string to be used later
var reactApp = {
__html: React.renderToString(<Router history={history}>{Routes}</Router>)
};
var head = Helmet.rewind();
//render the outer HTML and pass the already rendered app as props to be inserted to the same place as it would be on client.
var html = React.renderToStaticMarkup(<Html title={head.title} reactApp={reactApp} />);
callback(null, '<!DOCTYPE html>' + html);
}
//Html.js
//component runs only during static site generation, never runs on client
//inserts props.reactApp to the exact place where client side renedering does
var React = require('react');
var Html = React.createClass({
render: function() {
return (
<html lang="en">
<head>
<title>{this.props.title}</title>
<script type="text/javascript" src="https://fb.me/react-0.13.3.min.js" ></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
</head>
<body>
<div id="content" dangerouslySetInnerHTML={this.props.reactApp} />
<script type="text/javascript" src="/bundle.js" charset="utf-8"></script>
</body>
</html>
);
}
});
module.exports = Html;
IMHO better solution than using ejs, because you need to use/learn one tool less. I would love to see this as official example in this repo.
I don't think you need either a .ejs
template or a React component for the "base HTML". I usually do something like this to keep it simple...
In a file called base-html.js
I would have:
export default `<!doctype html>
<html>
<head>
[...]
</head>
<body>
<div id="root">%PLACEHOLDER%</div>
<script src="script.js"></script>
</body>
</html>
`;
And to compile the template for use in my static site render function I would just...
const html = require('./base-html').replace(
/%PLACEHOLDER%/,
ReactDOMServer.renderToString(<RoutingContext {...renderProps} />)
);
KISS :)
I've found ES6 template strings also work well as a default :wink:
export default function appTemplate (htmlRenderedByReact, title, assets) {
return `
<!doctype html>
<html lang='en'>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
</head>
<body>
<div class='js-app-shell'>${htmlRenderedByReact}</div>
<script src='${assets.index}'></script>
</body>
</html>
`
}
Even better :+1:
Or why not with ES6 arrow functions as well... ;)
export default (htmlRenderedByReact, title, assets) => `
<!doctype html>
<html lang='en'>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
</head>
<body>
<div class='js-app-shell'>${htmlRenderedByReact}</div>
<script src='${assets.index}'></script>
</body>
</html>
`
Thanks for all the tips!
I don't have access to the repo anymore that caused me to ask this question, which makes it difficult for me to test these answers. So I'm not sure if I should close this issue or not. I might be able to do up a test project after christmas?
If you are happy with the answers I guess you can close the issue :)
Will do
@jonathanp in the ReadMe and your example, where do the renderProps come from ? I keep getting undefined when I try and console.log them but I'm not sure where they originate from or their importance ....
If you are just starting with static-site-generator-plugin consider getting inspiration from VaclavSynacek/react-isomorphic-static-site-generator-boilerplate. It does not follow the static-site-generator-plugin README exactly to a point (does not use ejs for example), but it is a working 5 page example, running right after git clone
on local and it even has a live demo running in gh-pages.
I'm not sure what ./template.ejs would look like in your example. Are you able to provide an example or a link to an example please?