/static-site-generator-webpack-plugin

Minimal, unopinionated static site generator powered by webpack

Primary LanguageJavaScriptMIT LicenseMIT

Build Status Coverage Status Dependency Status npm

static site generator webpack plugin

Minimal, unopinionated static site generator powered by webpack.

Provide a series of paths to be rendered, and a matching set of index.html files will be rendered in your output directory by executing your own custom, webpack-compiled render function.

This plugin works particularly well with universal libraries like React and React Router since it allows you to prerender your routes at build time, rather than requiring a Node server in production.

Install

$ npm install --save-dev static-site-generator-webpack-plugin

Usage

Ensure you have webpack installed, e.g. npm install -g webpack

webpack.config.js

const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');

const paths = [
  '/hello/',
  '/world/'
];

module.exports = {

  entry: {
    'main': './index.js'
  },

  output: {
    filename: 'index.js',
    path: 'dist',
    /* IMPORTANT!
     * You must compile to UMD or CommonJS
     * so it can be required in a Node context: */
    libraryTarget: 'umd'
  },

  plugins: [
    // `main` is the bundle name sepcified in the `entry` section above.
    new StaticSiteGeneratorPlugin('main', paths, {
      // Properties here are merged into `locals`
      // passed to the exported render function
      greet: 'Hello'
    })
  ]

};

index.js

Sync rendering

module.exports = function render(locals) {
  return '<html>' + locals.greet + ' from ' + locals.path + '</html>';
};

Async rendering (callbacks)

module.exports = function render(locals, callback) {
  callback(null, '<html>' + locals.greet + ' from ' + locals.path + '</html>');
};

Async rendering (promises)

module.exports = function render(locals) {
  return Promise.resolve('<html>' + locals.greet + ' from ' + locals.path + '</html>');
};

Default locals

// The path currently being rendered:
locals.path;

// An object containing all assets:
locals.assets;

// Advanced: Webpack's stats object:
locals.webpackStats;

Any additional locals provided in your config are also available.

Custom file names

By providing paths that end in .html, you can generate custom file names other than the default index.html. Please note that this may break compatibility with your router, if you're using one.

module.exports = {

  ...

  plugins: [
    new StaticSiteGeneratorPlugin('main', [
      '/index.html',
      '/news.html',
      '/about.html'
    ], locals)
  ]
};

Scope

If required, you can provide an object that will exist in the global scope when executing your render function. This is particularly useful if certain libraries or tooling you're using assumes a browser environment.

For example, when using Webpack's require.ensure, which assumes that window exists:

const scope = { window: {} };

module.exports = {
  ...,
  plugins: [
    new StaticSiteGeneratorPlugin('main', paths, locals, scope)
  ]
}

Compression support

Generated files can be compressed with compression-webpack-plugin, but first ensure that this plugin appears before compression-webpack-plugin in your plugins array:

const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  ...

  plugins: [
    new StaticSiteGeneratorPlugin(...),
    new CompressionPlugin(...)
  ]
};

React Router example

The following example uses React Router v1.0.0-rc1 with history.

import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import { createHistory, createMemoryHistory } from 'history';
import { Router, RoutingContext, match } from 'react-router';

import routes from './routes';
import template from './template.ejs';

// Client render (optional):
if (typeof document !== 'undefined') {
  const history = createHistory();
  const outlet = document.getElementById('outlet');

  ReactDOM.render(<Router history={history} routes={routes} />, outlet);
}

// Exported static site renderer:
export default (locals, callback) => {
  const history = createMemoryHistory();
  const location = history.createLocation(locals.path);

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    callback(null, template({
      html: ReactDOMServer.renderToString(<RoutingContext {...renderProps} />),
      assets: locals.assets
    }));
  });
};

Related projects

  • react-router-to-array - useful for avoiding hardcoded lists of routes to render
  • gatsby - opinionated static site generator built on top of this plugin

License

MIT License