Another Webpack Intro

Sep 08, 2016
Javascript, Node
~15min
Share on Twitter

No React etc. just pure webpack!

Let’s not beat around the bush here, there are a lot of basic introductions to webpack.

IMHO, some are good, some go off on tangents, some didn’t really tell me what I wanted to know when I was picking it up.

The goal here is to make you familiar with the basic concepts of webpack and go over some of the basics of how to use it. There will be nothing about getting your React project off the ground or how to integrate it with gulp etc.

If anything is unclear, please leave a note!

For those in camp TL;DR there is some code to play with here! Or if you just want to get on with it, scroll down to “Example”.

What do I think of webpack permalink

Before I dive in, I have been asked what I think of webpack.

I‘ll admit, I was certainly skeptical at first. I felt it was a little counter-intuitive, the docs kinda had me confused and I wasn’t 100% if I was using it right.

If you feel like this, hang on in there. If you’re willing to give it another shot, it gets better. Have a read through this intro and see how you feel after.

Once you get your head round what webpack aims to do and how it does it, begin to think about your source in the “webpack” way and become familiar with looking at config files you might really grow to like webpack.

I’ve actually grown to really like it.

Why another intro? permalink

It seems webpack is not the most intuitive tool to grasp. Head over to the docs and you might be overwhelmed by not only the content, but the sheer mass of it!

Some of my “favorite” quotes in the docs comments;

The document is so obscure, I read so many times,but still can not figure out how to use it comprehensively and cleanly.

Thought I was the only one…! I came here from angular 2.It’s just a module bundler,it’s just a tool,yet it feels like rocket science with this bloated and all-over-the-place documentation

What are the advantages of this over using streams in Gulp? I don’t understand.

great tool, awful documentation

That last one is particularly succinct. From my experience, webpack is a greal tool. But to appreciate how great it is, you need to at the very least have a basic understanding of it and I feel a lot of people may give up at the first hurdle because of this. Especially, if you are coming from a tool like Gulp where any valid JS will work and things are a little more intuitive.

That’s the purpose of this post. To give a basic understanding and show how to do some of the basic things you might want to achieve.

Not a task runner permalink

webpack is not a task runner. It is a bundler.

This is the most important concept to let sink in. Those familiar with tools like browserify should be OK with this idea. For those that are not, forget about the notion of tasks.

In fact, you may not need that task runner of choice you’ve been using at all.

What does it do? permalink

webpack is a bundler.

You write your configuration file and get on with writing your project code. When you run webpack, it works out your project dependency tree and calculates the required assets for your project. What you get in return is a dump of the static assets and bundle in a defined location that are required to make your project work.

webpack abstracts you away from worrying about things like concatenation of scripts and publishing of static assets.

You specify what assets you need and when in your source using CommonJS/Node style syntax. webpack handles the rest. The best part is that those assets can be any assets, not just JavaScript. You can even require syntax that would need to be processed such as CoffeeScript, SASS, LESS etc. This may not feel quite right to start with but once you’re familiar with it, it‘s actually pretty good.

The aim is to make everything a module and only bundle the things we need. Imagine we are working on a project with components. With webpack we can treat a component as a module that requires it’s own styling and other assets. We don’t need to write some clever task runner logic to handle it. This will make sense with the walkthrough further down but for now imagine a TODO component that has it’s own styles.


            javascript
            
          /**
  * TODO component
*/
require('./todo.scss');
var Todo = function () { ... };
export default Todo;

Concepts permalink

Before I walkthrough a common webpack setup, it’s key to go over some of the main concepts you’ll be seeing in a configuration file. For a start, here is a configuration file.


            javascript
            
          const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer      = require('autoprefixer');
const webpack           = require('webpack');
const path              = require('path');

const IS_DIST = (process.argv.indexOf('--dist') !== -1) ? true : false;

const config = {
  devServer: {
    port: 1987
  },
  entry: {
    app: './src/script/app.js',
    /* create a vendor chunk for grabbing vendor resources */
    vendor: [
      'lodash'
    ]
    /* Create another chunk for a different page etc. */
    // app2: './src/script/app2.js'
  },
  output: {
    path: `${__dirname}/public`,
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        include: /(src\/script)/,
        query: {
          presets: [
            'es2015'
          ]
        }
      },
      {
        test: /\.styl$/,
        include: /(src\/)/,
        // loader: 'style-loader!css-loader!postcss-loader!stylus-loader'
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!stylus-loader?paths=src/style')
      }
    ]
  },
  resolve: {
    root: [
      path.resolve('./src/script'),
      path.resolve('./src/style')
    ],
    extensions: [ '', '.js', '.styl' ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/markup/index.html',
      filename: 'index.html',
      chunks: ['vendor', 'app']
    }),
    new webpack.optimize.CommonsChunkPlugin(
      /* chunkName= */'vendor',
      /* filename= */'vendor.js'
    ),
    /* Example if we wanted to create a second page */
    // new HtmlWebpackPlugin({
    //   template: './src/markup/index.html',
    //   chunks: ['app2'],
    //   filename: 'app.html'
    // }),
    new ExtractTextPlugin('app.css'),
    /* If --dist is present in process opts then minimize bundles */
    (IS_DIST) ? new webpack.optimize.UglifyJsPlugin() : function () {}
  ],
  postcss: function () {
    return [ autoprefixer ];
  }
}

module.exports = config;

This lives in the root of our project and is used by webpack to create your bundles. We are exposing “config” to webpack.

Entry permalink

This is where webpack starts. This is where we define the entry point to our app. We can define more than one entry point. The easiest example would be;


            javascript
            
          entry: {
  app: 'src/script/app.js'
}

“app.js” becomes our starting point. This would be where we initialize our app and pull in global things such as our base styles etc.

Output permalink

Where are bundles and assets get dumped.

Chunks permalink

I won’t go too much into chunks because I believe it could be a topic in itself. They are as they sound, chunks of your codebase. There are three types; entry, normal and initial.

The simplest to explain would be the entry chunks, each named entry becomes a chunk with that name. So in our entry, we would have an entry chunk named “app”. But we can much further than this when we start discussing “code splitting”.

Loaders permalink

I mentioned previously that you may be able to get rid of your task runner completely. Loaders handle the transformation of required modules.

For example; let’s say we require some styles for a component and they are written with SASS. The browser needs CSS. Loaders handle the preprocessing for us.

You can either use loaders directly in your source. This style requires that loaders are piped with ! and prefix the module path.


            javascript
            
          require('css-loader!sass-loader!./styles/base.sass');

Or you can define loaders within your configuration so you can simply do;


            javascript
            
          require('./styles/base.sass');

More on loaders later.

Plugins permalink

For everything else, there’s a plugin.

There seems to be some confusion around the difference between plugins and loaders on the webpack docs;

It’s not immediately clear what differentiates a plugin from a loader. The loader has the interface of input source -> output source, but what about plugin? What is their purpose? I’m sure I will figure it out shortly, but current docs do not do a good job of differentiating.

To me, loaders handle processing individual files whether they need transformation or not. I need this module, the loader handles grabbing it.

Plugins are there to handle everything else. Scenarios that can’t be handled by loaders. We can’t put a concrete label on them because they don’t really have limits. In some cases they will do things that are bundle specific, like minification of source. But in other cases they may be generating their own files to go alongside the bundle. An example being the html-webpack-plugin that will create markup files for you based on the bundle and defined options.


Example permalink

I’m going to try and replicate the majority of my gulp-boilerplate;

  • Markup compilation
  • Stylesheet compilation(Stylus w/ autoprefixing)
  • Script compilation(Babel)
  • Static server with automatic livereload and style injection

We use npm to install required packages and I am using a self-documented Makefile for running commands (This is just a preference of mine to avoid using npm run-scripts, you can use run-scripts if you like)

NOTE:: You can grab the source from here if you get stuck or need some guidance.

Source structure permalink

+ repo
  + src
+ markup
      - index.html
+ script
      + components
        + binarizer
          - binarizer.js
          - binarizer.styl
      + modules
        - convert.js
      - app.js
+ style
      - base.styl
- Makefile
- package.json
- webpack.config.babel.js

NOTE:: instead of using “webpack.config.js”, I am using “webpack.config.babel.js”. This is possible with the use of “babel-register”.

Configuration file permalink

Here is the resulting configuration file for reference(likely to be updated).


            javascript
            
          const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer      = require('autoprefixer');
const webpack           = require('webpack');
const path              = require('path');

const IS_DIST = (process.argv.indexOf('--dist') !== -1) ? true : false;

const config = {
  devServer: {
    port: 1987
  },
  entry: {
    app: './src/script/app.js',
    /* create a vendor chunk for grabbing vendor resources */
    vendor: [
      'lodash'
    ]
    /* Create another chunk for a different page etc. */
    // app2: './src/script/app2.js'
  },
  output: {
    path: `${__dirname}/public`,
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        include: /(src\/script)/,
        query: {
          presets: [
            'es2015'
          ]
        }
      },
      {
        test: /\.styl$/,
        include: /(src\/)/,
        // loader: 'style-loader!css-loader!postcss-loader!stylus-loader'
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!stylus-loader?paths=src/style')
      }
    ]
  },
  resolve: {
    root: [
      path.resolve('./src/script'),
      path.resolve('./src/style')
    ],
    extensions: [ '', '.js', '.styl' ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/markup/index.html',
      filename: 'index.html',
      chunks: ['vendor', 'app']
    }),
    new webpack.optimize.CommonsChunkPlugin(
      /* chunkName= */'vendor',
      /* filename= */'vendor.js'
    ),
    /* Example if we wanted to create a second page */
    // new HtmlWebpackPlugin({
    //   template: './src/markup/index.html',
    //   chunks: ['app2'],
    //   filename: 'app.html'
    // }),
    new ExtractTextPlugin('app.css'),
    /* If --dist is present in process opts then minimize bundles */
    (IS_DIST) ? new webpack.optimize.UglifyJsPlugin() : function () {}
  ],
  postcss: function () {
    return [ autoprefixer ];
  }
}

module.exports = config;

Handling JavaScript and our first entry point permalink

Let’s start with JavaScript and creating a basic bundle. We have two entries in our configuration file;


            javascript
            
          entry: {
  app: './src/script/app.js',
  /* create a vendor chunk for grabbing vendor resources */
  vendor: [
    'lodash'
  ]
},

Our first entry point is going to be “app.js”;


            javascript
            
          import '../style/style.styl';
import 'lodash';
import { Binarizer } from './components/binarizer/binarizer';
const el = document.querySelector('.my-element');
const myBinarizer = new Binarizer(el);

Don’t worry about the logic, just focus on the importing.

Hmm. That looks like ES6. Yes, I’m using “import” rather than “require”. That won’t be supported everywhere but it’s use is possible using a loader. Introducing our first loader definition.

To convert our ES6 code to browser happy code, we will use the babel-loader.


            javascript
            
          {
  test: /\.js$/,
  loader: 'babel',
  include: /(src\/script)/,
  query: {
    presets: [
      'es2015'
    ]
  }
},

Loader definitions all take the same options so you don’t have to worry about different config options like with say something like Grunt.

  • The test key is used to check whether a module should be using this loader.
  • The loader key defines which loader to use with this module.
  • The include key(preferred over the excludes key according to docs) tells webpack to only use the loader on matching modules within the defined directories.
  • The query key is for additional options.

Here we are simply saying whenever there is a .js file loaded from within “src/script” use the babel-loader to convert the script.


Back to what we’re importing. Notice that we are also importing lodash. We can import vendor scripts just as we would in node. However, instead of packaging them within in our bundle, we may choose to keep them separate in their own bundle such as vendor.js.

This is possible by creating another chunk and using our first plugin;


            javascript
            
          entry: {
  app:./src/script/app.js’,
  /* create a vendor chunk for grabbing vendor resources */
  vendor: [
    ‘lodash’
  ]
},

The plugin we will use is the CommonsChunkPlugin. This will create another bundle with a given name based off of the provided chunk.


            javascript
            
          plugins: [
  new webpack.optimize.CommonsChunkPlugin(
    /* chunkName= */'vendor',
    /* filename= */'vendor.js'
  )
]

When we run webpack;


            shell
            
          webpack --progress --colors

We’ll expect to get back app.js and vendor.js. But, where will they go?

This is what we need the output key for in our configuration. This defines where our bundled assets get dumped and with what name.


            javascript
            
          output: {
  path: `${__dirname}/public`,
  filename: '[name].js'
},

This means that our assets will get dumped in the public folder. The use of “[name]” means that they will have a filename matching their chunk name. You can also use other options here such as “[hash]”.

It is also worth making a remark here about “code splitting”. I’ve shown a simple way here with using named chunks and use of the CommonsChunkPlugin. But later down the line when you’re dealing with more complex applications you’ll most likely be needing to give performance some consideration. Webpack does have some(and I hate to use the word) magic up it’s sleeve. Let’s consider a single page application with several views. If we load the scripts for all those views on the first page this can slow down our app on initial load and this will impact performance. What if we could make it so that our app only pulled in bundled chunks of logic when they were required? For example, if I had an app where I could view and edit photos, I wouldn’t need the editing logic if I landed on the view page. Webpack makes this possible with anonymous chunks and the use of require.ensure. Not a real world example but an easy way to show the code working would be to alter app.js to use require.ensure to get our Binarizer module and then show our app as loaded on first load;


            javascript
            
          import 'style.styl';
import 'lodash';
const el = document.querySelector('.my-element');
document.body.className = 'loading';
require.ensure(['components/binarizer/binarizer'], (require) => {
  const Binarizer = require('components/binarizer/binarizer');
  const myBinarizer = new Binarizer.Binarizer(el);
  document.body.className = '';
});

This is a real simple example of code splitting and it’s a topic which could have it’s own article on it’s own so I strongly encourage looking it up!

Handling Markup permalink

Our scripts aren’t much good without some markup to use them in.

When I first started with webpack, working out how to keep my markup within my src folder wasn’t instantly obvious.

I’m a firm believer in source belonging in the src folder. I don’t want to commit parts of the public folder etc.

The html-webpack-plugin is really good for this scenario. You create your markup templates and let the plugin publish them to your output path.

Under “src/markup” we have index.html;


            html
            
          <html lang="en-us">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Webpack playground</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1.0"/>
    <meta name="description" content="webpack playground"/>
  </head>
  <body>
    <h1>webpack-playground</h1>
    <div class="my-element"></div>
  </body>
</html>

Note that we omit any script, link and style tags. webpack magic will handle this!

Under plugins, we simply declare the use of our plugin to create our markup files;


            javascript
            
          new HtmlWebpackPlugin({
  template: './src/markup/index.html',
  filename: 'index.html',
  chunks: ['vendor', 'app']
}),

Note that we declare the chunks to be included. This gives us the ability to pick and choose which chunks we could need for which pages.

To create multiple pages, we use multiple instances of the plugin.

Handling Styles permalink

Handling styles is actually pretty nice once you’ve got into it. It’s certainly something I feel compliments the whole modular approach.

First things first, the project is using Stylus so we are going to need another loader;


            javascript
            
          {
  test: /\.styl$/,
  include: /(src\/)/,
  loader: 'style-loader!css-loader!postcss-loader!stylus-loader'
}

This will inline our styles within our bundle. I’m not a massive fan of this, it just doesn’t sit right with me. I prefer a native CSS file for the majority. No worries, digging around would lead you to reading up on stylesheets. Here you’ll find that there’s a happy medium if you prefer this approach;

Create one css file per initial chunk (see Code Splitting) and embed stylesheets into additional chunks. (recommended)

Cool!

If you read up on it, you’ll find that using the extract-text-webpack-plugin you can extract the styles and create the file you want. This just requires changing our loader definition and adding the plugin.


            javascript
            
          /* Loader definition */
{
  test: /\.styl$/,
  include: /(src\/)/,
  loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!stylus-loader')
}
/* Plugins */
new ExtractTextPlugin('app.css')

Our markup will get the link to app.css automagically and we can now import our styles where we need them.

Autoprefixing, How? permalink

Easy. We’ll need to use the postcss-loader. After going and looking at the docs, we can see that it’s as simple as adding the loader to our loader chain for our style files and declaring that the postcss-loader uses autoprefixer by adding the following to the root of our configuration;


            javascript
            
          postcss: function () {
  return [ autoprefixer ];
}

You can provide options to autoprefixer if required.

Where to include global styles permalink

This is one that might seem off at first. You’ll be looking to include your base/global styles at the entry point to your application. We are doing this in app.js


            javascript
            
          import '../style/style.styl

Global styling assets such as variables need to be imported by the modules that need them.

Component Specific Styles permalink

The nicest thing I believe with styles is that with webpack, you can just pull in styles where you need them, you don’t have to micro manage it with your task runner. For example, let’s say I have some component with it’s own specific styles.


            javascript
            
          /**
  * Some awesome component
*/
// Import component specific styles
import './style/component.styl';
// Import utils
import '../utils';
// Awesome logic goes here

Importing Vendor Styles permalink

What about vendor styles? In most cases we are going to pull in some common CSS utilities like normalize.

I tend to do this in the root of my styles. Prefixing a vendor name with ~ will find it.


            javascript
            
          @import '~normalize.css'
@import 'base.styl'
@import './components/button.styl'

Handling Assets permalink

I’m not going to touch too much on the handling of images and other assets. Essentially anything that you need to be an asset becomes a module so you need to require/import it. If I need an image then I need to import it. This will mainly become prevalent in projects that use libraries such as React;


            javascript
            
          const imageSrc = import '../img/profile.png';
const image = document.createElement('img');
image.src   = imageSrc;

In the majority of cases, there is going to be a loader for what you need or a plugin to help you.

Remember. Google is your friend.

Optimizing Code permalink

I’ll briefly touch upon the optimization of code. In most projects, you’ll have some way of creating a distributable version of your source or a production ready version.

A common example would be minifying your JavaScript. In a task runner you’re likely to add a step for minifying the output with uglify.

With webpack it’s a little different. This is because you’re working against the bundle. If you’re going to minify one thing, you’re minifying all the things! I kinda like this though.

How? permalink

As we are in node land, we can add an additional option when we invoke webpack. It will mean nothing to webpack, but we can use it in our configuration file. When we want to optimize our source we can invoke webpack with an additional dist option


            shell
            
          webpack --progress --colors --dist

Inside our configuration we can create a reference that checks for the existence of this option;


            javascript
            
          const IS_DIST = (process.argv.indexOf(--dist’) !== -1) ? true : false;

All that’s left is to determine whether a plugin should be used or not based on this reference. Inside our plugins we add the following;


            javascript
            
          (IS_DIST) ? new webpack.optimize.UglifyJsPlugin() : function () {}

That’s all there is to it. When it runs, all outputted assets will be minified where appropriate.

Serving It permalink

The last piece to our webpack starter pack is serving up all of our assets so we can see them working in the browser. We also want watching and some livereload goodness thrown in.

Simply, webpack-dev-server handles it all.

It accepts the same options as webpack does when we run that. The only difference is that we require reloading and style injection. For this, we need to use the hot and inline options along with the d option for watching;


            shell
            
          webpack-dev-server --progress --colors --hot -d --inline

Bonus:: Handling Ugly Imports permalink

You might have noticed some of those “import” statements we’ve been using get pretty ugly when we start using relative paths.


            javascript
            
          import '../styles/style.styl';
import '../../modules/someModule';

Imagine how bad this gets when the our codebase grows and we have further nested directories etc.

Luckily, webpack is ahead of the game on this. If we have a src folder where all our source lives we can tell webpack about root paths to resolve and use as a lookup. For example, to look for modules with a root path of “src/styles” and “src/scripts”.


            javascript
            
          const path = require('path');
.....
resolve: {
  root: [
    path.resolve('./src/scripts'),
    path.resolve('./src/styles')
  ]
}

NOTE:: For path resolution within style files, you’ll need to refer to loader documentation for your loader of choice.

Bonus:: Setting Up Tests permalink

You may be wondering how to set up creating test source with webpack. It isn’t straight-forward when first using webpack. Let’s have a quick look at getting set up with mocha/chai.

First things first. I prefer to structure my source so that my tests are relative to the entities being tested. For example, if I have


            shell
            
          src/script/component/superComponent.js

then I will also have;


            shell
            
          src/script/component/superComponent.test.js

This comes into play later on.

If you start searching for ways to set up tests with webpack, you’ll see various things such as loaders for mocha etc.

Getting set up is much simpler than that. Yes, webpack will only dump out one bundle, but we can pass webpack a different config when we want in order to generate a test bundle for mocha to use.

If we create a new config named webpack.config.test.babel.js, we can use a testing root as our entry point.


            shell
            
          webpack --config webpack.config.test.babel.js --progress --colors

But won’t we have to import every test from the entry point?

No. There is a little trick. What we do is create an entry point that will do all the lifting for us. Create a test building entry point at test/test.build.js;


            javascript
            
          var context = require.context('../src/script/', true, /.*\.test\.js/);
context.keys().forEach(context);
module.exports = context;

This trick simply searches the given directory and imports all modules that end with .test.js.

What about when a module tries to import styles?

We only care about the importing of scripts for our unit tests, so in our test config we tell webpack to essentially ignore anything other than scripts using a special loader known as the null-loader.


            javascript
            
          {
  test: /\.styl$/,
  include: /(src\/)/,
  loader: 'null-loader'
}

Our test config will look something like the following;


            javascript
            
          const webpack = require('webpack');
const config = {
  entry: {
    test: './test/test.build.js'
  },
  output: {
    path: `${__dirname}/test`,
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'babel',
        include: /(src\/script)/,
        query: {
          presets: [
            'es2015',
            'react'
          ]
        }
      },
      {
        test: /\.styl$/,
        include: /(src\/)/,
        loader: 'null-loader'
      }
    ]
  },
  resolve: {
    extensions: [ '', '.js', '.jsx' ]
  }
}
module.exports = config;

To run our tests;


            shell
            
          webpack --config webpack.config.test.babel.js
./node_modules/bin/mocha test/test.js

That’s it! permalink

Yep. It’s just another webpack intro. It also may not be the clearest thing to follow(please leave notes and suggestions, I’ll do my best to clarify and make alterations if necessary).

But, this one covers some things which weren’t at first obvious to me and I feel are somewhat overlooked without having to dig through various blog posts and reems of documentation.

I can understand why so many of these intros and tutorials pop up. It’s not easy to write about. I can really sympathise with the webpack author. It’s a really great tool, but it’s pretty hard to write about.

You can grab a playground repo here to experiment with and play around with webpack.


            javascript
            
          const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer      = require('autoprefixer');
const webpack           = require('webpack');
const path              = require('path');

const IS_DIST = (process.argv.indexOf('--dist') !== -1) ? true : false;

const config = {
  devServer: {
    port: 1987
  },
  entry: {
    app: './src/script/app.js',
    /* create a vendor chunk for grabbing vendor resources */
    vendor: [
      'lodash'
    ]
    /* Create another chunk for a different page etc. */
    // app2: './src/script/app2.js'
  },
  output: {
    path: `${__dirname}/public`,
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        include: /(src\/script)/,
        query: {
          presets: [
            'es2015'
          ]
        }
      },
      {
        test: /\.styl$/,
        include: /(src\/)/,
        // loader: 'style-loader!css-loader!postcss-loader!stylus-loader'
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!stylus-loader?paths=src/style')
      }
    ]
  },
  resolve: {
    root: [
      path.resolve('./src/script'),
      path.resolve('./src/style')
    ],
    extensions: [ '', '.js', '.styl' ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/markup/index.html',
      filename: 'index.html',
      chunks: ['vendor', 'app']
    }),
    new webpack.optimize.CommonsChunkPlugin(
      /* chunkName= */'vendor',
      /* filename= */'vendor.js'
    ),
    /* Example if we wanted to create a second page */
    // new HtmlWebpackPlugin({
    //   template: './src/markup/index.html',
    //   chunks: ['app2'],
    //   filename: 'app.html'
    // }),
    new ExtractTextPlugin('app.css'),
    /* If --dist is present in process opts then minimize bundles */
    (IS_DIST) ? new webpack.optimize.UglifyJsPlugin() : function () {}
  ],
  postcss: function () {
    return [ autoprefixer ];
  }
}

module.exports = config;