Skip to content

Proxy Content from URL with Webpack Dev Server

December 21st, 2017 - SoftwareTutorial

An application I’m working with has a large amount of static files (path starting with '/files/') deployed on a mounted volume in Docker. They are subsequently served via nginx. for local development, I thought of two options:

  1. Add files to the local dev server (e.g. copy assets)
  2. Build a proxy to pipe the request to the nginx-served site

The first option is somewhat restrictive:

  • I’d have to make sure the files are kept in sync with the latest version.
  • I’d have to integrate the syncing process with the build scripts.
  • Just mounting the volume is not a solution as the data would need to be shareable on the remote machine.

Therefore, only the second option seems to be viable, with the following conditions:

  • The web server needs to be running at all times
  • It needs to be accessible locally without authentication

Configure the Dev Server

Webpack has a development server one can use locally. Normally, it only serves resources from contentBase:

config.devServer = {
  contentBase: path.join(__dirname, 'dist')
  // ...
}

Fortunately, it also offers pre- and post-processing via the before and after. In our case, implementing before would allow us to replace the default process for the request to '/files/' with a custom implementation:

var request = require('request')

const before = function before(app) {
  app.get('/files/*', (req, res) => {
    request('http://<nginx.server.address>:<port>' + req.path).pipe(res)
  })
}

if (config.devServer.before) {
  const proxy = config.devServer.before
  config.devServer.before = function replace(app) {
    before(app)
    proxy(app)
  }
} else {
  config.devServer.before = before
}

Our function before(app) is intercepting requests to '/files/':

const before = function before(app) {
  app.get('/files/*', (req, res) => {

We perform a request via prepending the nginx server’s address and port:

request('http://<nginx.server.address>:<port>' + req.path)

Then we just pipe the response from the server to our local dev server:

      .pipe(res)
  });
};

Once the behaviour is fixed, we chain the behaviour:

if (config.devServer.before) {
  const proxy = config.devServer.before
  config.devServer.before = function replace(app) {
    before(app)
    proxy(app)
  }
} else {
  config.devServer.before = before
}

At this point, all requests to '/files/*' will be tunnelled to the remote server transparently.

Few Notes

Note: You might want to perform different transformations (instead of just prepending the server details) or add some environment variables (e.g. proxy).

Note: If you can get away with copying assets locally (or even including them in your project), you can do so. I personally find the idea of having static project assets in a separate location as a necessary evil in this particular case.

HTH,

Share on
Reddit
Linked in
Whatsapp

A little experiment: