Skip to content

moxystudio/webpack-isomorphic-dev-middleware

Repository files navigation

webpack-isomorphic-dev-middleware

NPM version Downloads Build Status Coverage Status Dependency status Dev Dependency status

The webpack-dev-middleware, but for isomorphic applications.

Showcase

Installation

$ npm install webpack-isomorphic-dev-middleware --save-dev

The current version works with webpack v2, v3 and v4.
You might get a peer dependency warning when using webpack v2 or v3 but you may ignore it.

Motivation

Building applications powered by webpack with server-side rendering (isomorphic/universal apps) is hard.

When making a production build, you must compile both the client and server. When developing, we want to rebuild the client & server and bring in the new compiled code without restarting/reloading the application. This is complex, especially setting up the development server.

To make your development workflow easier to setup, webpack-isomorphic-dev-middleware offers an express middleware that:

  • Looks for code changes in both the client and the server and automatically compiles them
  • Optimizes compilation by using in-memory filesystem
  • Delays responses until the aggregated compiler finishes
  • Adds isomorphic to res.locals, which includes the webpack stats and the methods exported in your server file
  • Offers beautiful compilation reporting into your terminal
  • Receive status through OS notifications
  • Shows compilation errors in the browser on refresh, similar to the ones you get on the terminal

Usage

const express = require('express');
const webpack = require('webpack');
const webpackIsomorphicDevMiddleware = require('webpack-isomorphic-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');

const clientCompiler = webpack({ /* webpack client config */ });
const serverCompiler = webpack({ /* webpack server config */ });
const app = express();

// Serve any static files from the public folder
app.use('/', express.static('public', { maxAge: 0, etag: false }));
// Add the middleware that will wait for both client and server compilations to be ready
app.use(webpackIsomorphicDevMiddleware(clientCompiler, serverCompiler));
// You may also add webpack-hot-middleware to provide hot module replacement to the client
app.use(webpackHotMiddleware(clientCompiler, { quiet: true }));

// Catch all route to attempt to render our isomorphic app
app.get('*', (req, res, next) => {
    // res.isomorphic contains `compilation` & `exports` properties:
    // - `compilation` contains the webpack-isomorphic-compiler compilation result
    // - `exports` contains the server exports, usually one or more render functions
    const { render } = res.locals.isomorphic.exports;

    render({ req, res })
    .catch((err) => setImmediate(() => next(err)));
});

The middleware function is flexible and supports various signatures:

  • Two separate webpack compilers
const clientCompiler = webpack({ /* webpack client config */ });
const serverCompiler = webpack({ /* webpack server config */ });

app.use(webpackIsomorphicDevMiddleware(clientCompiler, serverCompiler, { /* options */ }));
const compiler = webpack([
    /* webpack client config */,
    /* webpack server config */,
]);

app.use(webpackIsomorphicDevMiddleware(compiler, { /* options */ }));
const isomorphicCompiler = webpackIsomorphicCompiler(
    /* webpack client config */,
    /* webpack server config */
);

app.use(webpackIsomorphicDevMiddleware(isomorphicCompiler, { /* options */ }));

Available options:

Name Description Type Default
memoryFs Either disable or enable in-memory filesystem (disabling decreases performance) boolean true
watchOptions Options to pass to webpack's watch object
watchDelay Delay calling webpack's watch for the given milliseconds number 0
report Enables reporting boolean/object { stats: 'once' }
notify Report build status through OS notifications boolean/object false
headers Headers to be sent when serving compiled files object { 'Cache-Control': 'max-age=0, must-revalidate' }
findServerAssetName Finds the server asset to require from the Webpack stats function first js asset from the first entrypoint

By default, findServerAsset selects the first JavaScript asset from first entrypoint. If that doesn't suit your Webpack configuration, you may change it:

{
    // Finds the asset with the `server` word in its name
    findServerAssetName: (stats) => stats.assets
        .map((asset) => asset.name)
        .find((name) => /\bserver\b.+\.js$/.test(name));
}

Tests

$ npm test
$ npm test -- --watch during development

License

MIT License