Painless universal prerendering for Webpack. Works great with html-webpack-plugin.
npm install prerender-loader

Painless universal prerendering for Webpack. Works great with
[html-webpack-plugin].
> 🧐 What is Prerendering?
>
>Pre-rendering describes the process of rendering a client-side application at
>build time, producing useful static HTML that can be sent to the browser
>instead of an empty bootstrapping page.
>
>Pre-rendering is like Server-Side Rendering, just done at build time to produce
>static files. Both techniques help get meaningful content onto the user's
>screen faster.
- Works entirely within Webpack
- Integrates with [html-webpack-plugin]
- Works with webpack-dev-server / webpack serve
- Supports both DOM and String prerendering
- Asynchronous rendering via async/await or Promises
---
- Features
- How does it work?
- Installation
- Usage
- DOM Prerendering
- String Prerendering
- Injecting content into the HTML
- Prerendering JavaScript Files
- Options
- License
prerender-loader renders your web application within Webpack during builds,
producing static HTML. When the loader is applied to an HTML file, it creates a
DOM structure from that HTML, compiles the application, runs it within the DOM
and serializes the result back to HTML.
---
First, install prerender-loader as a development dependency:
``sh`
npm i -D prerender-loader
---
In most cases, you'll want to apply the loader to your html-webpack-plugin
template option:
`diff
// webpack.config.js
module.exports = {
plugins: [
new HtmlWebpackPlugin({
- template: 'index.html',
+ template: '!!prerender-loader?string!index.html',
// any other options you'd normally set are still supported:
compile: false,
inject: true
})
]
}
`
What does all that punctuation mean? Let's break the whole loader string
down:
> In Webpack, a module identifier beginning with !! will bypass any configuredmodule.rules
>loaders from - here we're saying "don't do anything toindex.html
> except what I've defined here?string
>
>The parameter tells prerender-loader to output an ES module!
>exporting the prerendered HTML string, rather than returning the HTML directly.
>
>Finally, everything up to the last in a module identifier is the inline!
>loader definition (the transforms to apply to a given module). The filename of
>the module to load comes after the .html-loader
>
>Note: If you've already set up or raw-loader to handle.html
> files, you can skip both options and simply pass a template value of"prerender-loader!index.html"
>!
As with any loader, it is also possible to apply prerender-loader on-the-fly
:
`js`
const html = require('prerender-loader?!./app.html');
... or in your Webpack configuration's module.rules section:
`js`
module.exports = {
module: {
rules: [
{
test: 'src/index.html',
loader: 'prerender-loader?string'
}
]
}
}
Once you have prerender-loader in-place, prerendering is now turned on. Duringindex.html
your build, the app will be executed, with any modifications it makes to will be saved to disk. This is fine for the needs of many apps,
but you can also take more explicit control over your prerendering: either using
the DOM or by rendering to a String.
During prerendering, your application gets compiled and run directly under
NodeJS, but within a [JSDOM] container so that you can use the familiar browser
globals like document and window.
Here's an example entry module that uses DOM prerendering:
`js
import { render } from 'fancy-dom-library';
import App from './app';
export default () => {
render(
};
`
In all cases, asynchronous functions and callbacks are supported:
`js
import { mount } from 'other-fancy-library';
import app from './app';
export default async function prerender() {
let res = await fetch('https://example.com');
let data = await res.json();
mount(app(data), document.getElementById('app'));
}
`
It's also possible to export a function from your Webpack entry module, which
gives you full control over prerendering: prerender-loader will call the
function and its return value will be used as the static HTML. If the exported
function returns a Promise, it will be awaited and the resolved value will be
used.
`js
import { renderToString } from 'react-dom';
import App from './app';
export default () => {
const html = renderToString(
// returned HTML will be injected into
In addition to DOM and String prerendering, it's also possible to use a
combination of the two. If an application's Webpack entry exports a prerender
function that doesn't return a value, the default DOM serialization will kick
in, just like in DOM prerendering. This means you can use your exported
prerender function to trigger DOM manipulation ("client-side" rendering), and
then just let
prerender-loader handle generating the static HTML for whatever
got rendered.Here's an example that renders a [Preact] application and waits for DOM
rendering to settle down before allowing prerender-loader to serialize the
document to static HTML:
`js
import { h, options } from 'preact';
import { renderToString } from 'preact';
import App from './app';// we're done when there are no renders for 50ms:
const IDLE_TIMEOUT = 50;
export default () => new Promise(resolve => {
let timer;
// each time preact re-renders, reset our idle timer:
options.debounceRendering = commit => {
clearTimeout(timer);
timer = setTimeout(resolve, IDLE_TIMEOUT);
commit();
};
// render into
using normal client-side rendering:
render( , document.body);
});
`$3
When applied to a
.html file, prerender-loader will inject prerendered
content at the end of by default. If you want to place the content
somewhere else, you can add a {{prerender}} field:`html
{{prerender}}
`This works well if you intend to provide a prerender function that only returns
your application's HTML structure, not the full document's HTML.
$3
In addition to processing
.html files, the loader can also directly pre-render
.js scripts. The only difference is that the DOM used for prerender will be
initially empty:`js
const prerenderedHtml = require('!prerender-loader?string!./app.js');
`---
Options
All options are ... optional.
| Option | Type | Default | Description |
| ------------- | ------- | ------------------ | ---------------------------------------------------------------------- |
|
string | boolean | false | Output a JS module exporting an HTML String instead of the HTML itself |
| disabled | boolean | false | Bypass the loader entirely (but still respect options.string) |
| documentUrl | string | 'http://localhost' | Change the jsdom's URL (affects window.location, document.URL...) |
| params` | object | null | Options to pass to your prerender function |
---
This is not an official Google product.
[html-webpack-plugin]: https://github.com/jantimon/html-webpack-plugin
[JSDOM]: https://github.com/jsdom/jsdom
[Preact]: https://preactjs.com