Is there a way to pre-generate the HTML structure of a (single route) React application directly in the HTML entry point?
Then the page will be able to display HTML (based on React initial state) before any JS is loaded.
I'm actually using webpack-html-loader but any other loader or plugin is welcome ;)
PS: May static-site-generator-webpack-plugin be of any help?
PS: I'm not using React Router
If you want to use static-site-generator-webpack-plugin you first need to build a bundle with webpack bundle.js
that exports a render function that takes following arguments.
locals
an object with various page metadata e.g. title
that go into component parameters (traditionally thought of as template variables).callback
a nodejs style (err, result)
callback that you will call with your rendered html as the value for result
e.g.
// entry.js, compiled to bundle.js by webpack
module.exports = function render(locals, callback) {
callback(null,
'<html>' + locals.greet + ' from ' + locals.path + '</html>');
};
It is in this function that you will instantiate your components (possibly via React Router if you want) and render them with ReactDOMServer.renderToString()
.
You will then specify the compiled bundle.js
as bundle
in your instantiation of StaticSiteGeneratorPlugin
as well as your concrete routes in paths
and in locals
an object containing the above mentioned metadata values.
var paths, locals; // compute paths from metadata files or frontmatter
module.exports = {
entry: {
bundle: './entry.js' // build bundle.js from entry.js source
},
...,
plugins: [
new StaticSiteGeneratorPlugin('bundle', paths, locals)
]
}
The keys you specify for locals
in webpack.config.js
in will be present in the locals
parameter of every call to render(locals, callback)
. They will be merged with path
, assets
and webpackStats
keys provided by the plugin.
If you want to load javascript code into your pages after rendering you could compile an additional page.js
entry to your webpack config that calls ReactDOM.render()
in the typical manner and then load that bundle in a script
tag emitted by in your render(locals, callback)
function in your bundle.js
(above). Ensure that page.js
mounts components to the same location in the DOM as they are when rendered by entry.js
(you will probably set an id
attribute on the parent element). You will also need to ensure that any location (i.e. route path) dependent variables align in both environments.
Check out the source code of Gatsby which also uses this plugin. You can also have a look at the source code for Phenomic for an alternative approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With