node package manager
Stop writing boring code. Discover, share, and reuse within your team. Create a free org »

super-awesome-webpack-plugin

Build Status Coverage Status dependencies Status

Super Awesome Webpack Plugin

A slightly opinionated Webpack plugin for generating static websites using React, React Router & Redux.

Requirements

  • Currently only tested on node v6.3.1 & 7
  • < 3.0.0
    • Webpack 1
  • 3.0.0 - Webpack 2

Install

npm install --save-dev super-awesome-webpack-plugin

Setup

webpack.config.js

Require plugin & build config

const SuperAwesomeWebpackPlugin = require('super-awesome-webpack-plugin');
const staticBuildConfig = require('./static.config');

Each site entry be matched to the sites build entries and added to its index.html

entry: {
    // site entry 
    home: path.join(__dirname, 'src/js/sites/order/home.js'),
    // site entry 
    product: path.join(__dirname, 'src/js/sites/order/product.js'),
    // style asset referenced by index.html's 
    style: path.join(__dirname, 'src/less', 'styles.less'),
    // vendor chunked .js asset referenced by index.html's 
    vendor: Object.keys(require('./package.json').dependencies)
}

New up the plugin and add it to the plugin array. The first parameter is the site configuration and the second parameter takes a webpack configuration object (everything in the site configuration is ran through webpack).

 
plugins: [
 
    new webpack.optimize.CommonsChunkPlugin({
        // These will be output as assets.webpack.vendor and assets.webpack.manifest in the template 
        names: ['vendor', 'manifest'],
        minChunks: Infinity
    })
    new SuperAwesomeWebpackPlugin(buildConfig, {})
]

Example Configuration

Example configuration file

/**
 * Template used to generate index.html files. See example below.
 */
const template = require('./template');
 
// Reducers 
const product_reducer = require('./src/js/redux/reducers/product');
const content_reducer = require('./src/js/redux/reducers/content');
 
const staticConfig = {
  dataDir: './data',
  sites: [
    {
        // All pages under this site will share this entry, template, and reducers 
        entry: 'main',
        template,
        component: './src/js/components/pages/Wrapper', // wrapper component that wraps each route component 
        /**
         * This is a bit of a hack, but until a better solution can be found this will work.
         * The plugin will look for a data file named 'index.json' at the base of dataDir and relate
         * it to this indexRoute.
        /*
        indexRoute: { component: './src/js/components/pages/Home' }
        pages: [
            /**
             * Pages dictate what index.html's get created. Each page must have a matching
             * .JSON file at /[dataDir]/[route].
             *
             * NOTE: If you use multiple pages per entry you will need to use something like react-router
             * to properly serve the correct page in the client.
             *
             * This site will generate four pages.
             * - /en_US/home/index.html
             * - /es_US/home/index.html
             * - /en_US/explore/index.html
             * - /es_US/explore/index.html
             */
            { route: '/*/home', component: './src/js/components/pages/Home' },
            { route: '/*/explore', component: './src/js/components/pages/Explore' }
        ],
        reducers: { content: content_reducer }
    },
    {
      entry: 'product',
      template,
      component: layout_component,
      pages: [
        { route: '/*/menu/product/*', component: './src/js/components/pages/Product'},
      ],
      reducers: { product: product_reducer, content: content_reducer }
    }
  ]
};

Example Data Directory

/data
    index.json // This is a copy of /en_US/home.json 
    /en_US
        home.json // /en_US/home/index.html 
        explore.json // /en_US/explore/index.html 
        /products
            product_1.json // /en_US/products/product_1/index.html 
            product_2.json // /en_US/products/product_2/index.html 
            product_3.json // /en_US/products/product_3/index.html 
    /en_US
        home.json // /es_US/home/index.html 
        explore.json // /es_US/explore/index.html 
        /products
            product_1.json // /es_US/products/product_1/index.html 
            product_2.json // /es_US/products/product_2/index.html 
            product_3.json // /es_US/products/product_3/index.html 

Example Template File

/**
 * Template must be a function that accepts a single configuration and returns a string.
 * assets = {
 *  html: <rendered html page>,
 *  state: <state object>,
 *  app: <path to js file>,
 *  webpack: {<all assets generated during webpack bundling>}
 * }
 *
 **/
export default function (assets) {
    return `
    <html lang="en">
        <head>
            <title>My Store</title>
            <script>
                window.__data = ${JSON.stringify(assets.state)};
            </script>
        </head>
        <link rel="stylesheet" type="text/css" href="/${assets.webpack.style.replace('js', 'css')}" />
        <body id="body">
            <div id="app">
                ${assets.html}
            </div>
            <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
            <script src="/${assets.webpack.manifest}"></script>
            <script src="/${assets.webpack.vendor}"></script>
            <script src="${assets.app}"></script>
        </body>
    </html>
    `
}

TODO

Project

  • Create example site
  • Tests & coverage reports

Core

  • Handle ES6 modules more seamlessly
  • Add ability to define asset-to-template mapping.
  • Integrate with react-router for configuration field mapping
  • Test/add webpack-dev-server support
  • Change template to accept generic objects
  • Locale needs to be handled better.
  • Abstract state management so users have more flexibility.

Page Builders

  • Base paths for data directories
  • Support localization in builder functions to reduce configuration noise (Partially complete)
  • Validation around configuration (Partially complete)
  • Remove multiPage flag in favor of a better architecture # super-awesome-webpack-plugin-example-site