Friday, 6 January 2017

webpack: resolveLoader / alias with query / options

Sometimes you write a post for the ages. Sometimes you write one you hope is out of date before you hit "publish". This is one of those.

There's a bug in webpack's enhanced-resolve. It means that you cannot configure an aliased loader using the query (or options in the webpack 2 nomenclature). Let me illustrate; consider the following code:

module.exports = {
  // ...
  module: {
    loaders: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        query: {
            entryFileIsJs: true
        }
      }
    ]
  }
}

module.exports.resolveLoader = { alias: { 'ts-loader': require('path').join(__dirname, "../../index.js") 

At the time of writing, if you alias a loader as above, then the query / options will *not* be passed along. This is bad, particularly given the requirement in webpack 2 that configuration is no longer possible through extending the webpack.config.js. So what to do? Well, when this was a problem previously the marvellous James Brantly had a workaround. I've taken that and run with it:

var config = {
  // ...
  module: {
    loaders: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        query: {
          entryFileIsJs: true
        }
      }
    ]
  }
}

module.exports = config;

var loaderAliasPath = require('path').join(__dirname, "../../../index.js");
var rules = config.module.loaders || config.module.rules;
rules.forEach(function(rule) {
  var options = rule.query || rule.options;
  rule.loader = rule.loader.replace('ts-loader', loaderAliasPath + (options ? '?' + JSON.stringify(options) : ''));
});

This approach stringifies the query / options and suffixes it to the aliased path. This works as long as the options you're passing are JSON-able (yes it's a word).

As I said earlier; hopefully by the time you read this the workaround will no longer be necessary again. But just in case....