Webpack

As we move towards larger Javascript projects, we start to need to add more and more files to our index.html . One way to manage all the files is to have the list of files automatically injected into the main page. The other way is to use a packing tool like Webpack and package all the source into one file. This also has the additional benefit of optimizing network calls and load speed.

Webpack, just out of the box will package all the source code into one file and output a bundle but it also has a large ecosystem of loaders and an active loader development community. Want ESNext support? Just add babel-loader and you’re ready to transpile. Webpack can also handle files other than Javascript code like HTML files, CSS, SASS, fonts, images and even markdown if you use the correct loader.

Yeah, Webpack is 🔥.

What can a loader do?

This loader ecosystem makes Webpack really powerful. A loader, put simply, is a bit of code that is used to extend or create the processing pipeline for a certain file extension. For example, we can use the image-loader to enable Webpack to process images and we can use aforementioned babel-loader to process ESNext Javascript and transpile it down to code that runs on a large range of browsers while still being able to use the latest features that come with new ECMAScript standards.

There is a long list of loaders on GitHub and it includes general purpose loaders like the css-loader , which can add CSS styles to the Webpack bundle to more specific loaders like the vue-loader , which helps Webpack pack Vue.js components. These loaders and make Webpack really powerful but what if we want to get even more specific, maybe we need Webpack to an internal enterprise process or have an idea that doesn’t exist as a loader yet? You can make your own loader!

I wrote a loader!

A little background before I get into the loader that I wrote. To get any AngularJS code packaged through Webpack, you have to have some way of getting the templates inserted into the Javascript code. Angular already has a way to do that in the form of a service called $templateCache . All you need to give it is a string that is the name of the template and the template, read from a file, also in string form. There is a loader out there called ngtemplate-loader that will take AngularJS templates and put them in the $templateCache . You just have to make a change to all files that have a template and require() the template before telling AngularJS about it.

This is where I saw an opportunity. What if we didn’t need to edit each file? The ngtemplate-loader that I mentioned works on HTML template files in your AngularJS project. What if we wrote a Webpack loader to work on the Javascript files, pull the template path out (stored in a key called templateUrl ), require() it and then let the ngtemplate-loader run on HTML files denoted by the path? That’s exactly what I did. I created a loader called auto-ngtemplate-loader that will run on all Javascript files and require in all the HTML template files automatically. No manual edits needed! It even supports multiple templates in a single file and changing the variable name that the template stored in to avoid name collisions.

#WYOL (Write Your Own Loader)

Webpack has made getting started writing a loader really really simple. There is a very well documented get started guide on Webpack’s website that walks you through setting up a loader project. The structure of a loader is really quite simple.

That’s it! We’ve just created a loader that returns the source unchanged. Of course, this specific loader isn’t very interesting but it helps illustrate the simple structure of a loader. You get the source and the source map passed into your loader. You do your stuff and then use this.callback to tell Webpack when you’re done and if there were any errors. Not only that, the this object in the loader function has all of the Webpack loader API accessible from it. 👍

Let’s write another loader but let’s make things more interesting — we’ll write a loader that removes console.log statements this time around. Time me.

And done!

The next step is to include our loader in the Webpack config and watch it work. Webpack loaders essentially create a processing pipeline for your code which gets evaluated in the reverse order that it is listed. For example, if our loader is listed after babel-loader , our loader will pass its results on to babel-loader . The source that we pass to this.callback then gets passed onwards to babel-loader as an argument.

My experience through the entire loader development process was exceptional and this only serves as a nod to the Webpack team for creating an easy to understand and easy to use API for extending Webpack. The codebase (with examples) is located on Github here. Go take a look at the code!

And now it’s time for a shameless plug.

auto-ngtemplate-loader

My loader is called auto-ngtemplate-loader . Once included (preferably last in the list so that it runs on the unmodified code), it will look through the Javascript files for the templateUrl key and add a line of code to the top of the file for each template it finds to import it so that ngtemplate-loader can put in AngularJS’s $templateCache .

If you have a large AngularJS codebase and have been thinking about switching to React or Angular or even if you’re just looking to get ESNext support, the first step you’re going to need to take is including Webpack in your build. auto-ngtemplate-loader can help ease some of the pain of converting a large AngularJS project over to a newer technology. You can add auto-ngtemplate-loader to your build by running npm install --save-dev auto-ngtemplate-loader . It’s fully documented and the repository has examples of a few cases that the loader handles well.

You can find the package here on npm and the code here on Github. Contributions are always welcome. 💯

Final thoughts

I got the idea to write a loader that automatically require s in HTML templates in your Javascript files so that Webpack can load them into AngularJS’s $templateCache . I thought that I would have to spend a few days testing things out before I could get a Webpack loader working but thanks to awesome documentation and guides from the Webpack team, I was up and running in about 15 minutes and done in less than half a workday. It was a breeze; extending Webpack is just as easy as using Webpack. That’s not very often the case and it’s very commendable. Many fist bumps are in order!