Webpack: How to Create Dynamic Entry & Output paths
Tags: javascript, webpack, tutorial
Published: 2019-09-01 20:48:48

# TLDR;
For those that don't want to read and just want the config file then here you go. All you need to do is change the **path string** passed to the `glob.sync(...)` method to match your needs.

```javascript
const glob = require('glob')
const path = require('path')

module.exports = {
    entry: glob.sync('./Projects/**/index.js').reduce((acc, path) => {
        const entry = path.replace('/index.js', '')
        acc[entry] = path
        return acc
    }, {}),

    output: {
        filename: './[name]/main.js',
        path: path.resolve(__dirname)
    }
}
```

The idea behind creating dynamic entry and output paths with Webpack might seem confusing. When I was trying to figure out the situation and began to ask around, I received a lot of "Why do you need that?".

The "why" is pretty simple. I've found myself in a situation where I'm writing a lot of one-off scripts, each doing something of their own and typically have nothing to do with another script. Because of this, I had some very niche needs for my project. Mainly, having the ability to build and minify each script into their own subdirectory.

The real magic of this **Webpack** config file is in the `entry` property. The `entry` property is capable of taking:

- `string`

```javascript
entry: './my/path/index.js'
```

- `string[]`

```javascript
entry: ['./my/first/path/index.js', './my/second/path/index.js']
```

- `object`

```javascript
entry: {
    'my/first/path': './my/first/path/index.js',
    'my/second/path': './my/second/path/index.js'
}
```

- `Function => string | string [] | object`

```javascript
entry: () => './my/path/index.js'
```

Now, let's dive into what's actually happening in this config file. Make sure to **read** the comments as I'm going to attempt to explain everything going on in the code itself as comments.

**webpack.config.js**
```javascript
/**
 * When passed a string, Glob will attempt to find each file that matches the
 * path given and return each path to the file as string[]
 */
const glob = require('glob')

/**
 * The Path API will be used to get the absolute path to the directory where we
 * plan to run Webpack
 */
const path = require('path')

module.exports = {
    /**
     * Pass Glob a relative path to each of our entry points
     * We will have different subdirectories inside of the Project directory so
     * we need to replace any of the directory names with a wildcard, **, which 
     * will recursively match any combination of directory names inside of any
     * number of subdirectories until it finds the index.js entry.
     * Then we use the Array.prototype.reduce method to iterate through the array
     * and return an object containing a path to each of our entry files
     * (index.js)
     */
    entry: glob.sync('./Projects/**/index.js').reduce((acc, path) => {
        /**
         * The "[name]" placeholder in the "output" property will be replaced
         * with each key name in our "entry" object. We need to make sure the
         * keys are a path to the "index.js" file but without the actual file
         * name. This is why we replace the file name, "index.js", with a string
         */
        const entry = path.replace('/index.js', '')
        /**
         * Here we start building our object by placing the "entry" variable from
         * the previous line as a key and the entire path including the file name
         * as the value
         */
        acc[entry] = path
        return acc
    }, {}),

    /**
     * The "output" property is what our build files will be named and where the
     * build file will be placed
     */
    output: {
        /**
         * Again, the "[name]" place holder will be replaced with each key in our
         * "entry" object and will name the build file "main.js"
         */
        filename: './[name]/main.js',
        /**         
         * We need to provide an absolute path to the root of our project and
         * thats exactly what this line is doing
         */
        path: path.resolve(__dirname)
    }
}
```

# Result

This is all you need to create dynamic entry & output paths with **Webpack**. The question now is what kind of project architecture does this example work with?

```
> node_modules
  package.json
  package-lock.json
> Projects
  ---- > Proj_1
         ---- index.js
  ---- > Proj_2
         ---- index.js
  webpack.config.js
```

After running our **Webpack** and building our files our project will then look like

```
> node_modules
  package.json
  package-lock.json
> Projects
  ---- > Proj_1
         ---- index.js
         ---- main.js  // new build file
  ---- > Proj_2
         ---- index.js
         ---- main.js  // new build file
  webpack.config.js
```