How to create multiple output paths in Webpack config

Does anyone know how to create multiple output paths in a webpack.config.js file? I'm using bootstrap-sass which comes with a few different font files, etc. For webpack to process these i've included file-loader which is working correctly, however the files it outputs are being saved to the output path i specified for the rest of my files:

    output: {
      path: __dirname + "/js",
      filename: "scripts.min.js"
    }

I'd like to achieve something where I can maybe look at the extension types for whatever webpack is outputting and for things ending in .woff .eot, etc, have them diverted to a different output path. Is this possible?

I did a little googling and came across this *issue on github where a couple of solutions are offered, edit:

but it looks as if you need to know the entry point in able to specify an output using the hash method eg:

var entryPointsPathPrefix = './src/javascripts/pages';
var WebpackConfig = {
  entry : {
    a: entryPointsPathPrefix + '/a.jsx',
    b: entryPointsPathPrefix + '/b.jsx',
    c: entryPointsPathPrefix + '/c.jsx',
    d: entryPointsPathPrefix + '/d.jsx'
  },

  // send to distribution
  output: {
    path: './dist/js',
    filename: '[name].js'
  }
}

*https://github.com/webpack/webpack/issues/1189

however in my case, as far as the font files are concerned, the input process is kind of abstracted away and all i know is the output. in the case of my other files undergoing transformations, there's a known point where i'm requiring them in to be then handled by my loaders. if there was a way of finding out where this step was happening, i could then use the hash method to customize output paths, but i don't know where these files are being required in.


Solution 1:

Webpack does support multiple output paths.

Set the output paths as the entry key. And use the name as output template.

webpack config:

entry: {
    'module/a/index': 'module/a/index.js',
    'module/b/index': 'module/b/index.js',
},
output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
}

generated:

└── module
    ├── a
    │   └── index.js
    └── b
        └── index.js

Solution 2:

I'm not sure if we have the same problem since webpack only support one output per configuration as of Jun 2016. I guess you already seen the issue on Github.

But I separate the output path by using the multi-compiler. (i.e. separating the configuration object of webpack.config.js).

var config = {
    // TODO: Add common Configuration
    module: {},
};

var fooConfig = Object.assign({}, config, {
    name: "a",
    entry: "./a/app",
    output: {
       path: "./a",
       filename: "bundle.js"
    },
});
var barConfig = Object.assign({}, config,{
    name: "b",
    entry: "./b/app",
    output: {
       path: "./b",
       filename: "bundle.js"
    },
});

// Return Array of Configurations
module.exports = [
    fooConfig, barConfig,       
];

If you have common configuration among them, you could use the extend library or Object.assign in ES6 or {...} spread operator in ES7.

Solution 3:

If you can live with multiple output paths having the same level of depth and folder structure there is a way to do this in webpack 2 (have yet to test with webpack 1.x)

Basically you don't follow the doc rules and you provide a path for the filename.

module.exports = {
    entry: {
      foo: 'foo.js',
      bar: 'bar.js'
    },

    output: {
      path: path.join(__dirname, 'components'),
      filename: '[name]/dist/[name].bundle.js', // Hacky way to force webpack   to have multiple output folders vs multiple files per one path
    }
};

That will take this folder structure

/-
  foo.js
  bar.js

And turn it into

/-
  foo.js
  bar.js
  components/foo/dist/foo.js
  components/bar/dist/bar.js

Solution 4:

You can now (as of Webpack v5.0.0) specify a unique output path for each entry using the new "descriptor" syntax (https://webpack.js.org/configuration/entry-context/#entry-descriptor) –

module.exports = {
  entry: {
    home: { import: './home.js', filename: 'unique/path/1/[name][ext]' },
    about: { import: './about.js', filename: 'unique/path/2/[name][ext]' }
  }
};

Solution 5:

If it's not obvious after all the answers you can also output to a completely different directories (for example a directory outside your standard dist folder). You can do that by using your root as a path (because you only have one path) and by moving the full "directory part" of your path to the entry option (because you can have multiple entries):

entry: {
  'dist/main': './src/index.js',
  'docs/main': './src/index.js'
},
output: {
  filename: '[name].js',
  path: path.resolve(__dirname, './'),
}

This config results in the ./dist/main.js and ./docs/main.js being created.