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.
To follow along in this series, you need the following requirements:
Let’s continue with the series.
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:
If you want to read more about ES6, you can check out the tutorial here.
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.
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.
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
.
When the installation is complete, we can now configure webpack to use the Babel loader for JavaScript files.
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 test
s 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
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.
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.
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.
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.