Initial static React HTML rendering with Webpack
Asked Answered
A

4

14

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

Armanda answered 2/2, 2017 at 20:10 Comment(3)
Have you tried server-side rendering?Lixivium
@Lixivium Can you be more explicit? Like sharing a webpack.config :D I need to generate static HTML at build timeArmanda
You can only do this if your whole page is static. No communication with API?Chaisson
S
10

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.

Scrag answered 18/2, 2017 at 11:56 Comment(0)
L
2

You should try server side rendering, it will let react render the first view of your app in a backend and deliver a static HTML. This boilerplate already comes with server rendering set up and you can learn more about it here

Lixivium answered 4/2, 2017 at 3:33 Comment(1)
Sure, but I need it in a full static way (without express).. initial HTML rendering should happen one, at build time (when running webpack).. Any example to share?Armanda
C
0

Jekyll is great static site generator which can be extended with custom ruby plugins. You need to enable WebPack to make Jekyll calls. See Plugging Webpack to Jekyll Powered Pages

Confidential answered 25/2, 2017 at 8:59 Comment(0)
C
0

Here you have a working example https://github.com/aganglada/preact-minimal/blob/master/config/webpack.config.js, if you like you can fork it and take a look at how this work all together.

Hope it helps :)

Chaoan answered 25/2, 2017 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.