Getting started with webpack - Part 4: Writing modern JavaScript

Introduction

In the previous part of the series, we learned what loaders are and how we can use loaders to handle other file types in webpack. We also applied what we learned in our project.

In this part of the series, we will dig deeper into webpack and see what else is possible. We will specifically try to use webpack to compile modern JavaScript, ES6+, so it’s available to all browsers.

Let’s get started.

NOTE: Source code of the application is available on GitHub.

Prerequisites

To follow along in this series, you need the following requirements:

  • Completed all previous parts of the series.
  • Basic knowledge of JavaScript.
  • Basic knowledge of the CLI.
  • A text editor. VS Code is recommended.
  • Node.js (>=6.11.5) and npm installed locally.

Let’s continue with the series.

What is ES6?

If you are a JavaScript developer, you’ll no doubt have heard of ECMAScript 6, which is also known as ES6 and ECMAScript 2015. This was a major update to the JavaScript language and it brought a lot of improvements over the older JavaScript version.

ES6 makes code a little shorter and a little more readable in some cases:

1// Pre-ES6
2    function helloWorld() {
3      return 'Hello world'
4    }

Above is a regular JavaScript function and below is the same function written using ES6 arrow functions:

1// ES6+
2    const helloWorld = () => 'Hello world'

ES6 also brings some new keywords to the mix like let and const which are supposed to replace the non-safe var keyword.

The let statement allows you to declare a variable with block scope:

1let name = 'Neo';
2    
3    if (1 == 1) {
4      let name = 'Ighodaro'
5    
6      console.log(name) // prints: Ighodaro
7    }
8    
9    console.log(name) // prints: Neo

The const statement allows you to declare a constant that cannot be changed:

1const name = 'Neo'
2    
3    if (1 == 1) {
4      name = 'Ighodaro'
5    }
6    
7    console.log(name)

Attempting to change a const as seen above will throw an error:

webpack-4-1

If you want to read more about ES6, you can check out the tutorial here.

Why the need to compile ECMAScript 6?

ECMAScript 6 is relatively new and not all browser versions support the syntax yet. Because of this, we need to use webpack to compile the code from ECMAScript 6 to something the browser already understands: ECMAScript 5.

When we write our code using the ECMAScript 6 syntax, we can then use a tool called Babel to compile the code to ES5 so all browsers can process the JavaScript.

Getting started with the Babel loader for webpack

For this part, we will be building off the code in part three. If you don’t have it already, you can download the project code from GitHub. We will be using the code there as a base for the modifications we are going to make going forward. When you have downloaded the project, open Part-3 in your code editor and follow along.

Installing Babel in our project

The first thing we need to do is install Babel. To install babel, cd to the root of the project and run the following command in your terminal:

    $ npm install --save-dev babel-loader @babel/core

The command above will install the babel-loader for webpack and also the @babel/core package which is a dependency of the babel-loader.

webpack-4-2

When the installation is complete, we can now configure webpack to use the Babel loader for JavaScript files.

Configuring the Babel loader

Open the webpack.config.js file and replace the contents with the following code:

1// File: ./webpack.config.js
2    let webpack = require('webpack');
3    let path = require('path');
4    
5    module.exports = {
6      mode: 'development',
7      entry: path.resolve(__dirname + '/src/index.js'),
8      output: {
9        path: path.resolve(__dirname + '/dist/assets'),
10        filename: 'bundle.js'
11      },
12      module: {
13        rules: [
14          {
15            test: /\.scss$/,
16            use: ['style-loader', 'css-loader', 'sass-loader']
17          },
18          {
19            test: /\.js$/,
20            exclude: /node_modules/,
21            loader: 'babel-loader'
22          }
23        ]
24      }
25    };

As seen in the code above, we added a new rule to the rules array. This rule tests for JavaScript files in our project, excluding the node_modules directory, and runs the JavaScript through the babel-loader which we installed earlier.

Now that we have webpack configured with the babel-loader let’s write some ES6 code and see if our new babel-loader will handle the code appropriately.

Open the src/utilities/random.js file and replace the contents with the following code:

1// File: ./src/utilities/random.js
2    export default class RandomStringGenerator {
3      generate() {
4        return this._rand() + this._rand();
5      }
6      
7      _rand() {
8        return Math.random()
9            .toString(36)
10            .substring(2, 15);
11      }
12    }

Above, we have replaced the function with a RandomStringGenerator class that does exactly the same thing. Classes were introduced in ES6 and are a very useful addition to JavaScript. We then export the class so we can import it into our main JavaScript file (and any other JavaScript file that may need it).

Next, let’s update the main JavaScript file to use the new class. Open the src/index.js and replace the contents of the file with the following code:

1// File: ./src/index.js
2    import RandomStringGenerator from './utilities/random';
3    import './style.scss';
4    
5    document.addEventListener('DOMContentLoaded', () => {
6      const randomStringGenerator = new RandomStringGenerator();
7      const randomStr = `Random String: <span>${randomStringGenerator.generate()}</span>`;
8      
9      window.setTimeout(
10        () => (document.getElementsByTagName('h1')[0].innerHTML = randomStr), 
11        0
12      );
13    });

Above, we have slightly modified the main JavaScript file to use the class we created and exported earlier. We also changed the syntax from the traditional JavaScript to ES6+ syntax. Now let’s compile to see what happens.

In your terminal, run the following command to install the npm dependencies and compile our assets using webpack:

1$ npm install
2    $ npm run build
webpack-4-3

When the installation and build finishes, open the compiled JavaScript file in dist/assets/bundle.js and towards the bottom, you’ll notice that although the build succeeded, the class was not compiled to ECMAScript 5 syntax and remains as ECMAScript 6.

webpack-4-4

So why is this happening? Well we need to create a .babelrc file. This is a configuration file for Babel. Without this file, Babel will not be configured and thus will do nothing.

In the root of the project, create a new .babelrc file and paste the following contents into the file:

1// File: ./.babelrc
2    {
3      "presets": ["@babel/preset-env"]
4    }

Alternatively, you can define the Babel configuration in the package.json file by adding the babel property to the JSON file like so:

1{
2      // [...]
3      
4      "babel": {
5        "presets": [
6          "es2015"
7        ]
8      }
9      
10      // [...]
11    }

Now that we have Babel configured, let’s move on to installing the Babel env preset, which enables transforms for ECMAScript 6+. To install the preset, run the following command:

    $ npm install @babel/preset-env --save-dev

@babel/preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller! - Babel documentation.

This will install the dependency and after the installation is complete, we can build the assets using webpack:

    $ npm run build

Now when the build is complete, you can open the dist/assets/bundle.js file and look for the affected area. You should see that unlike before where the class declaration was not converted to ES5, it is now compiled by Babel to ES5.

webpack-4-5

The code is not the easiest to read but if you look well you will see that the class has been compiled down to ES5 and will now work across older browsers. Let’s test it. In your terminal, run the following command to serve the Node.js server that comes with the code:

    $ node dist/server.js

If you visit http://localhost:3000, you should see the same output with no changes even though we are now using ES6 syntax in the code.

webpack-4-6

Conclusion

In this part of the series, we have learned how to use Babel to compile JavaScript files written in ES6+ syntax. However, webpack is a lot more powerful than this. We will dive a little deeper in the next part.

The source code to this application is available on GitHub.