Don’t Fear the Webpack

Complaining about things is fun.  My favorite one lately is that ‘getting a project started is so much harder now- back in the day, we just dropped a script tag at the bottom of the page and were off to the coding’.

And that used to be true- when ‘frontend development’ really just meant some form validation and simple page interactions and $ as far as the eye could see (jQuery, not money).  But the landscape has changed- grown, really.  Using modern frameworks and patterns, we can create much more interactive, responsive applications with much less work.  But with great power comes great responsibility- and in this case, that means a build process.

I dabbled in Gulp and Grunt- both were very useful- but was always intimidated by Webpack.  I think my early experiences with Angular 2 contributed to this.  Early on, Angular 2 configuration was done in SystemJS (at least in our project’s first iterations).  It was tricky and tempermental and tough to wrap my head around, but eventually, I was able to get it to work and even make useful updates.

Then we started looking at Webpack as an alternative.  I’d read some blog posts and it seemed to be the wave of the future- making things like lazy loading routes, minification, and even tree-shaking easy to handle.  But the process of manually migrating our existing project to Webpack proved to be a bit over my head.  We would need a dev server and a scss loader and a typescript config and a module loader- and this is just for the development process.  None of the awesome production build gains were even in view yet!  I had jumped in the deep end and am not a great swimmer.

When our team switched our project over to the Angular-CLI, however, Webpack came along with it.  No config necessary- the ng command takes care of that- and really does deliver on all the things (our production build version of the app became 3 times faster).  They don’t let you see the webpack.config file when you use the CLI- and that’s probably for the best in my case.  It takes care of so much that it would be quite intimidating to look at for someone just getting started with Webpack- and would be much easier to really muck things up than actually improve anything.  If/when the project is advanced enough that we need something the CLI can’t provide, then we’ll go digging.

Despite my initial intimidation, the performance gains were so good that I started looking at Webpack for my other projects.  My mistake: I started looking at config options others had used before really digging into the basics.  Sometimes this is great- getting started with Angular or React, I find it’s best to just generate a project and start experimenting with it/changing things.  It lets me see how the framework handles certain things- and if it won’t do what I want, then I can dig in to see what makes it tick.

But for Webpack to really ‘click’, I had to start from the beginning.  One current project on  my plate is updating an old php application to a node backend.  While we’re at it, we are also updating some of the frontend javascript (which was written circa 2003).  After a couple days, I discovered that it is possible to live without ES6, but I’d really rather not.  So, I installed Webpack and Babel and started from scratch.

This is part of the tradeoff I mentioned at the top of the post.  The time spent installing and configuring Webpack was not technically time moving forward with the project- no features were migrated to the new layout during that time- but the faster dev experience will more than make up for that in the end.  We get to use import statements and template strings and all that current generation javascript goodness.  Not to mention the possible performance gains when we incorporate a production build.

Webpack is for more than just single page apps, and doesn’t have to be complicated.  My project’s webpack.config file is current less than 20 lines and give me access to all ES6 and module loading (thanks to an assist from Babel).  With one line (and a couple node modules), I could add support for React/JSX transpiling as well.  It doesn’t have to be complicated- though I’m sure eventually it will.  If I want that great power (minifcation and tree-shaking and lazy loading and so on), I’ll have to extend this- but it sure was easy to get started.

module.exports = {
  entry: {
    adminPage: './static/js/src/admin/page.js',
    adminDashboard: './static/js/src/admin/dashboard.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'static/js/dist')
  },
  module: {
    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]
  }
};

One note on the above
In the output section, the ‘filename’ property seems a bit odd. That [name] in brackets is a cool tip I learned- it automatically grabs the name of the entry property.  So, if you have more than one bundle (we will have a different one depending on the page the user is on), you can tell the output to just create a bundle with those names.  For example, in this case, the config builds two bundles: adminPage.bundle.js and adminDashboard.bundle.js.  After that, it’s up to me to remember to put the correct script tag for each bundle in the correct html file and we are good to go!