duncanhall
duncanhall

Reputation: 11431

Setup webpack hot dev-server with a Node backend for production

I have a front-end application bundled with webpack, which is served by and talks to a Node backend server.

Webpack hot dev server is running on 8080. Node backend is running on 1985.

I want to serve index.html from Node, but want assets served from the hot dev server during development. To achieve this I have:

Set an absolute publicPath value in webpack config:

  output: {
    publicPath: 'http://localhost:8080/'
  },

And used absolute URLs in index.html to point to the hot dev server:

<script src="http://localhost:8080/webpack-dev-server.js"></script>
<script src="http://localhost:8080/js/vendors.js"></script>
<script src="http://localhost:8080/js/bundle.js"></script>

So I can run the hot dev server and run my Node server and browse to http://localhost:1985. Everything is great.

But when I come to deploy / run in production, this is definitely not what I want. I'd like relative URLs for vendors.js and bundle.js and I definitely don't want to include the webpack-dev-server.js script.

I could use Handlebars or some other templating on the server to specify the absolute / relative paths, but it wouldn't provide a clean way of removing the hot dev server script. I could also have different index files for each setup, but this seems like it would quickly lead to bugs.

How can this be best be structured / deployed to enable use of the hot dev server in development, while still allowing for the whole thing to be deployed and served via Node in production?

Upvotes: 2

Views: 1319

Answers (2)

Richard Scarrott
Richard Scarrott

Reputation: 7033

For this very reason I stopped using webpack-dev-server and instead use the combination of webpack-dev-middleware / webpack-hot-middleware as the latter allow you to mount them in an existing express server.

My server basically does this:

const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./webpack.config.js');

const app = express();

if (process.env.WEBPACK_DEV_SERVER === 'true') {
    const config = webpack(config);
    app.use(webpackDevMiddleware(compiler));
    app.use(webpackHotMiddleware(compiler));
} else {
    app.use(express.static(path.join(__dirname, './dist'));
}

app.use((req, res) => {
    res.status(200).send(`
        <!doctype html>
        <html>
        <head>
            <title>App</title>
        </head>
        <body>
            <div id="root"></div>
            <script src="/bundle.js"></script>
        </body>
        </html>
    `);
});

You can see a complete example in the 60fram.es react boilerplate

Upvotes: 0

suarezsm
suarezsm

Reputation: 11

We're currently doing the templating approach you suggested for the paths and sorta mitigated the ugliness of the webpack-dev-server.js script tag by introducing an environment variable that specifies whether or not we're 'building' or 'developing'.

If you're using gulp as a task runner (we are), you can set them with process.env.NAME = VALUE.

If you're using npm builds you can add them via the command line with --NAME VALUE.

The very last step for our backend server then is to create the variables that then fit into our index.html template:

    <%
    // connect the hot-reload dev server
    if (mode === 'dev') {
        print("<script type='text/javascript' src='" + webpackURL + "/webpack-dev-server.js'></script>");
    }
    %>
    <script type="text/javascript" src="<%= webpackURL %>/js/bundle.js"></script>

Upvotes: 1

Related Questions