Webpack and Babel
Webpack and Babel are vital tools for any frontend developer. What are the 'need to knows' for these ubiquitous packages?
Jerry Skrip finally finished typing his report on the complicated relationship between monkeys and bananas. He proofreads it and realizes his uses a lot of new-fangled terminology that his boss may not understood. He approaches his boss’s lackey – ahem, assistant – Billy Babel and asks him to take a look, hoping Billy can dumb down – err, “simplify” – the language. Fortunately, Billy knows his boss well and is happy to review Jerry’s report to avoid a frustrated boss from raving at Jerry over his own insecurities. Billy scans the report, and cutting out Jerry’s new age buzz words (“Synergise”? “Moving the goalpost”? Billy questions what any of these words have to do with bananas) he presents Jerry with a readable copy. Grateful, Jerry returns to his desk, eager to impress his boss.
Cross browser compatibility issues have plagued JavaScript since inception. Even when only two browsers ruled the seas, developers had to be cognizant of processing differences between Internet Explorer and Netscape. jQuery came along in 2006, with functions that abstracted away differences. But JavaScript language tools continued to grow; new and sophisticated tools such as Promises and arrow functions were added at part of ECMA2015 (also known as ES6). Not all browsers kept up to date with the new syntax, and a need arose for a compiler1 so developers could write ES6 syntax without the browser throwing a tantrum. Babel is a JavaScript compiler for converting ES6 code into backwards compatible version.
Babel processes ES6 syntax and converts it into an older version of JavaScript. The package accepts a configuration file with instructions on what transformations to apply, where to output the compiled files, and even what browsers to be compatible. Plugins allow the developer to customize which transformations Babel needs to perform - most ES6 transformations have their own plugin. Only including specific plugins helps cut down on compile time and package size. Let’s look at an example below.
First, install Babel with the following command.
Our project folder setup has an index.html file and a ‘src’ folder where our JavaScript files will live. Our awesome website will display some text and update it when a user clicks a button. Here is what our project looks like:
Note: I am not running a local server – I’m simply opening the index.html file in the browser. When I click the button, the text changes.
Cool right? Web development is so easy. The astute reader may have noticed an arrow function passed as an argument to the ‘addEventListener’ function. Arrow functions are an ES6 addition. While this browser parses ES6 syntax, that might not hold true for all. This is where Babel shines.
Start by creating a babel.config.json file in the root directory to customize the compilation process. The config file will tell Babel what plugins to use. Plugins are transformations Babel applies to the source code. There are many plugins to choose from - for now only the arrow function2 one is included.
You’ll also need to install the plugin as a dependency:
With our configuration complete and the package, Babel is ready to compile. By default, Babel will compile files in the ‘src’ folder of the root directory. Run the following command to compile the scripts into backwards compatible JavaScript.
Below is the compiled ‘button-click.js’ file, now without an arrow function. Change the ‘src’ attribute in the script tag to ‘lib’, and the browser will load the compiled JavaScript
What happens if we want to use more ES6 syntax, such as block scoping (let and const) or template literals? Currently, the configuration file will only transform arrow functions. Plugins exist for block scoping and template literals, and following the steps above would add each one individually. Managing three plugins is not a tall order, but performing these steps each transformation would get unwieldy. Fortunately, Babel has a solution called presets. Presets wrap plugins together, so only one package needs to be installed. ES6 transformations are all kept in the same preset. Refactor the configuration file to take advantage of presets:
Install the preset package:
Run the same command as above, and viola. All the ES6 code compiled with only one package.
Each new feature brings more JavaScript code, but keeping all our code in one file is bad practice. Eventually, it becomes prudent and necessary to spread the code across files. While making life easier on the developer, each file still needs to be downloaded separately by the browser. Wouldn’t it be nice if the browser only had to download one file with all the JavaScript, while the developer wrote code in separate files? This is where Webpack comes in.
Jerry Skrip is ready to turn in his groundbreaking report on the monkey-banana connection when a co-worker condescendingly asks him if he’s going to turn in the report “like that”. Puzzled, Jerry asks him what he means by “like that”. The demeaning co-worker clarifies; he tells Jerry he does not like how the report seems to be divided up into mini-reports - each section with a different title and paper clipped separately. Jerry, who wrote each section individual, assumed it would be acceptable to turn it in this way. The co-worker shook his head, and encouraged him to ask Willy Webpack for help. Willy reviewed Jerry’s work, and shuffled papers around to turn it into one neat and complete document. He was even nice enough to remove some extraneous pages that did not add to the report. Grateful for Willy and Billy’s work in editing his report, he walks confidently into his bosses office.
What is Webpack?
Webpack is a bundler, specifically a bundler for static files - it gathers all the JavaScript files and compiles them into one file (or bundle). A bundler is a program that accepts an ‘entry’ file as an input and recursively pulls all dependencies and outputs a single file. This is particularly important for JavaScript, since reducing the number of file downloads a browser needs to make improves performance. Below are steps for adding Webpack to your project and bundling the JavaScript files.
Like Babel, Webpack needs to be installed as a project dependency.
Main functionality into ‘index.js’, which will server as the entry file for bundling. The logic for adding an event to the button lives here, and from ‘index.js’ we import the button function. For good measure, the ‘updateText’ variable was placed in a JSON file. Webpack doesn’t technically need a configuration file (webpack will bundle without one) its best to have one. Incorporating Babel into the bundling process, a requires a configuration file
Points of interest for the configuration file: the ‘entry’ is the file location Webpack begins to bundle. The ‘output’ is the file location the final bundle will be saved. Note that although the ‘output’ field takes additional attributes (such as ‘path’), ultimately it resolves itself to a file location, just like the ‘entry’ field. Running the following command will build bundle and place the bundle in the dist folder.
A small update to our HTML file to make sure we load the newly bundled script, and we are off to the races.
Note the Babel-compiled scripts are not bundled - those live in the ‘lib’ folder, not the ‘src’ folder. Instead of Webpack to bundling the compiled files, the configuration file will instruct Webpack to use a loader to transform / compile the code during bundling. Below are the new addition to the configuration object.
The ‘module’ field is where ‘loaders’ are configured - Webpacks method of transforming the source code. The ‘test’ field accepts a regular expression and tells Webpack which files to transform (in this case, the regular expression will resolve to all JavaScript files). The ‘loader’ field inside the ‘use’ object is the loader name - additional options for the loader can be passed within the ‘option’ field (note the ‘options’ object mirrors the object created with babel.config.json). Once babel-loader is installed with npm, run the Webpack command again to compile during the bundling process. The final output is a singular JavaScript file compiled to work across browsers.
Enterprise level applications don’t need you to come in and fix their webpack configuration (at least I hope – condolences to the poor souls who got stuck with webpack work on Day 1) – bundling will be taken care of. But having the skills to configure Webpack is helpful in personal projects, specifically if the project uses a JavaScript framework like React or Vue. Speaking from experience, it’s a mental lift knowing the specifics of importing the various frontend components into files is handled. React and Vue work best when utilized as the entire frontend (as opposed to a component here and there), and Webpack helps facilitate all of it.
I know from experience that Webpack can be frustrating - I used some colorful language the first time I tried to configure Webpack for a React project. Bundling for web frameworks is out of scope for this guide, but the fundamentals covered here will make it easy to implement a customized configuration for any of the major JavaScript frameworks3. Happy coding.
A compiler is a programming term for converting one form of code to another. Compilers typically run in the background – after all, our computers can’t understand JavaScript; it needs to be transformed into machine code. Our browser handles this compilation for us.
Plenty of additional resources exist, but I recommend checking out the official documentation first.