The Wonderful Wide World of webpack: Unpacking Awesomeness

Aaron Diffenderfer JavaScript, Technology Snapshot Leave a Comment

In the past couple of years, webpack has come a long way. It continues to rapidly evolve and revolutionize the way we bundle JavaScript and more. For some of us that have been doing development for more than a few years, seeing an amazing tool like webpack and all of its abilities is mind-blowing. If only it had come into existence a bit sooner…

If you’re like me, you may have stumbled across webpack, hearing about its gazillion configuration options, along with a bunch of plugins, numerous ways to optimize your bundle, and more. So much that it all makes your head spin and you begin to feel overwhelmed as you attempt to make sense of it. That’s honestly how my journey began with Webpack.

My first exposure to it…Ejecting the webpack.config.js file from an AngularCLI project just to see what the all the hype was about and to see what I had been missing out on the past few years. After getting past the initial shock of the number of lines of code and the seemingly large structure (how I felt after my first few glances, having to shield my eyes and take a few deep breaths), I started to see many of the benefits. This continued as I read through the webpack documentation, various blogs, and StackOverflow (every developer’s most-accessed site) and as I began trying out a variety of configurations for some actual projects.

As I discovered, webpack can be used with zero config or configured literally in 8,675,309 ways, plus or minus a handful. And there about just as many blogs that cover all of the variations and flavors.

In this post, however, the goal is to highlight some tips & tricks along with features I’ve found to be particularly useful and reasons why you should be using webpack – if you haven’t already started.

Note: if you’re totally new to webpack, check out these prior blogs for some great background information and examples: Pack It Up, Pack It In and BackboneJS with Webpack: A lesson in optimization.

Unpacking Features – How to webpack

Source maps

As a developer when you’re debugging, there’s no more important tool than source maps. Prior to our conversion to webpack for a client, we were using browserify with the grunt process. To get source maps to work there, it required jumping through various hoops, putting your right foot in, putting your right foot out, etc.

webpack makes it a whole lot easier. And one of the great features related to source maps is the devtoolModuleFilenameTemplate. This option gives you the ability to customize the naming within the maps. Rather than having to weed through arbitrarily named folders and filenames within the debugger searching to find where your code is located, you can make the naming as descriptive as you want.

Personally, I like having the correlation to the file location on disk – it just makes sense. So to accomplish this small but amazing feat, it just takes adding the following little line of code. (Well, you technically also need the require statement for path.)

devtoolModuleFilenameTemplate: info => 
    'file:///' + path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')

In the debugger, your source files will now be shown in a folder structure mimicking what’s on disk.

Configuration

Like I mentioned at the beginning, there are many ways you can choose to structure your webpack configuration file. A popular method is to divide your file into at least 3 parts: 1) common, 2) dev, and 3) prod.  The common file contains the core webpack configuration and the other two files contain the development and production-specific options accordingly. Then a merge tool like webpack-merge is used to make the magic happen.

This is a perfectly good avenue. For me, though, I like to keep the plugins to a minimum if possible – at least for the simpler things. It means one fewer module that I need to worry about someone still having a maintainer for over time. And, in this case, since we’re just dealing with JavaScript, why not use just use…JavaScript.

See Also:  What's New in JUnit 5.2

The initial premise is still the same as building a common configuration module and then exporting it. Then, instead of using a plugin to merge the configs, the base config just gets required in the next, more specific module. It’s ultimately imported in the actual using project. With this idea, you can build a hierarchy of configuration and make customizations at each one.

And in our case, we’ve turned each level into its own npm module with a package.json containing the more specific dependencies as well. The result is one dependency that a developer can drop into their project and instantly have the webpack configuration, the base dependencies, and even scripts that they need to be productive.

Here’s an example of a hierarchy that we’ve built:

  • Base – basic webpack config that all projects need
    • SPA – webpack config that applies to all SPAs
      • AngularJS
      • Angular 2+
    • npm – webpack config that applies to all npm library modules

Here is a sample of some of the general configuration structure:


const ...;

var baseConfig = env => {
 // With env, you can access environment variables

  return {
    mode: 'development',

    entry: {
      "main": ["./src/main/modules/app.js"],
      "styles": ["./src/main/scss/main.scss"],
    },

    resolveLoader: {
      "modules": [
      ]
    },
    output: {
    },
    plugins: [],

    module: {
      rules: []
    },
    devServer: {
    }
  };
}

module.exports = baseConfig;

SPA layer
const myBaseConfig = require('my-base-config');

module.exports = (baseConfig, env) => {
  if (!baseConfig) {
    baseConfig = {};
  }

  let currentConfig = myBaseConfig(baseConfig, env);

  // This isn't needed for some project types but is needed for all of my SPAs so it's moved to this level
  currentConfig.plugins.push.apply(currentConfig.plugins, [
    new HtmlWebpackPlugin({
      template: './src/main/index.html',
      minify: {
        collapseWhitespace: false,
        removeComments: false,
        removeRedundantAttributes: false
      }
    })
  ]);

  return currentConfig;
};
Project webpack.config.js
const baseSPAConfig = require("my-base-spa-config");

module.exports = (baseConfig, env) => {
  if (!baseConfig) {
    baseConfig = {};
  }
  let currentConfig = baseSPAConfig (baseConfig, env);
  // Do more project specific stuff if needed

  return currentConfig;
}

Since you’re just working with JavaScript, you have the ability to manipulate the objects as needed. Your only “limitations” are that you’ll still need to follow the webpack schema and to use common sense.

webpack-dev-server

For developers, it’s the simple things in life that make the biggest differences. With webpack-dev-server, that statement is very true as one of the coolest options is the overlay. You wouldn’t necessarily know what it provides solely by its name, but once you’ve included it in your project, your life will be forever changed. The code to add the overlay is very simple:

overlay: true

or as an object:

overlay: {
  warnings: true,
  errors: true
}

So what does this one-liner/object do for you? Glad you asked.

With this code in your devServer config block, you are given feedback of build problems directly within your browser viewport. When you make a change in your code, you expect to see an updated rendered result in the browser. But if there’s a build warning or error, you wouldn’t know it unless you a) don’t see the result of the change you’ve made in the browser and b) check the terminal where you kicked off the build. The overlay takes care of that and gives you virtually instant visual feedback.

Here’s an example of an overlay:

Note: As of January 2018, webpack-dev-server has officially gone into maintenance mode, but it is still very useful and will still serve a purpose for some time. It is being replaced by webpack-serve, “a lean, modern, and flexible webpack development server”. As of yet, the overlay functionality hasn’t been made available within webpack-serve. If/when it does, it will likely be an add-on that you can supply to webpack-serve.

Other Notifiers

If you’re looking for an even more obvious notifier during development, webpack-build-notifier and webpack-notifier both tie into the operating system notification systems. This again is a simple win as a developer. Rather than having to rely on the terminal or even browser, you’ll get the notification directly from the OS in the system tray.

See Also:  Getting to Know Custom CSS Properties

In addition to visual notifications, there are even webpack plugins like sounds-webpack-plugin that provide audial notification and allow customizations.

Unpacking Benefits – Why to webpack

webpack itself somehow makes you want to use webpack. Reading through various stories of projects on other blogs, you’ll read drastic improvements in their benchmark numbers. We haven’t completed running statistics yet on our projects, but the initial results show major time gains.

But that’s not the only reason we converted, in fact, there are many. As background, the client we worked with was using a grunt-based architecture which worked great for years but had quickly become out of date. So here are some quick highlights of our “why”:

  • Exposed code smells – When I converted one of the projects to use webpack, I uncovered that grunt had been allowing some bad practices. For instance, we were missing require statements in a few places but grunt still magically pulled in the files. webpack, on the other hand, is much more explicit about handling files and it immediately balked at the errors.
  • Smaller bundles – Grunt is just a task runner and does what you tell it to do, while webpack does so much for you without you having to think about it. Tree-shaking is one of those areas that’s built-in to its nature. It’s smart enough to only pull in what’s really needed and prunes the stuff that isn’t. If you don’t require/import it, webpack won’t include it. The result is that our bundles don’t have a lot of unnecessary images, fonts, CSS, modules, etc. and therefore the bundled files are much smaller in size.
  • Number of plugins – With grunt, we were using over 20 different plugins to manage the build process, whereas webpack needed only 5 to accomplish the same results. And with those grunt plugins, each had configuration options and files. Webpack handles quite a bit inherently and continues to integrate the critical aspects directly into its core.
  • Reduced technical debt – Many of the grunt plugins being utilized were either deprecated, needing maintainers, or out of date. This led to a lot of technical debt and even contributed to being stuck with older npm versions. While it’s possible for this to occur when using any project, it should be less likely to occur with how everything is now structured. And the community has a whole has embraced webpack so much so that it’s going to be around for years to come, continuing to evolve and help everyone through the upgrade process to future versions.
  • And so much more – I could go on, but I think you get the idea.

In the end, the bigger question is “why not webpack?”

Unpacking More – What’s next with Webpack

As I mentioned in the very beginning, Webpack has evolved drastically in the last few years. I have no doubt that it will continue at its mind-boggling speed, revolutionizing the development world.

Webpack 4 arrived earlier this year, and no sooner was it released, that there were already talks of release 4.5 and 5. Each promises more development enhancements, amazing new features, speed improvements, and far more. Here are some github links to follow and articles to check out for additional insights and details:

Unpacking is a never-ending process. So stay tuned for more as Webpack continues its great efforts to improve the development experience and abilities and as we continue to unpack it all.


About the Author
Aaron Diffenderfer

Aaron Diffenderfer

Aaron is a consultant with Keyhole Software with 15+ years in the software industry. He has worked with a variety of languages all the way from archaic ones like SmallTalk (one of his favorites) and COBOL (the language of the dark ages before dirt existed) to the more modern world of Java and C#. His current focus is on the latest and greatest with JavaScript, Angular, and SPAs. With various companies in other lives, he has also been a corporate trainer and professor and even is an official inventor with a patent in the works.


Share this Post

What Do You Think?