Introduction to Webpack 4

The Swiss Army Knife of modern JavaScript Development.

What is Webpack?

Well that’s simple — Webpack is a module bundler for JavaScript applications.

Now, to back it up a little bit let’s see how modules work in JavaScript. Modules, as in any other programming language, help you break down your code into smaller separate parts. This pattern helps in managing growing complexity by keeping concerns separate into their independent parts. Simply put, modules help organize code.

Before ES6, this could be done using different script files and then loading each of them separately with a <script> tag in our HTML. This had many disadvantages like fetching multiple files, maintaining correct order of the script tags to avoid accidentally breaking any dependent code and many more. But thankfully, ES6 brought support for modules with import and export keywords but they are not yet fully supported across all environments (browser as well as node).

Enter Webpack — It enables you to write your code in modules and it packages all the modules into one (or more) bundle. Webpack lets you use the modules and all its goodness without worrying about support. Apart from JavaScript, it can also take in other types of asset including (but not confined to) CSS, fonts, image, HTML, etc. and then transform them into the webpack acceptable format.

Webpack is extremely powerful and can be extended to do impressive things using the concept of loaders and plugins, that we will explore next.

NOTE: This might be the best time to start using webpack if you have been avoiding it earlier. Webpack had a reputation of being hard for beginners to get started with but webpack 4 changes all that with smart zero config mode based configuration. Webpack 4 makes getting started a breeze.

The core concepts of Webpack

We will skim through a little bit of theory part before we jump into some basic webpack config setup.

Entry

Webpack uses dependency graph to decide which modules need to bundled. This means Webpack starts from a single module and processes all its direct and indirect dependencies to form the entire dependency graph and then bundle all the necessary modules.

The Entry Point determines where webpack should start from to build out its internal dependency graph.

./src/index.js is the default entry value in webpack 4.

Output

The Output determines where the webpack is supposed to emit the bundles it creates and how it names them.

./dist/main.js is the default output value in webpack 4.

Loaders

Loaders in webpack are what enables it to handle files that are not JavaScript (webpack on its own only understands JavaScript). Loaders various types of files and transforms them into valid modules that webpack can understand.

Read more about the most common loaders in the webpack community — https://webpack.js.org/loaders/

Plugins

Plugins are the most powerful feature of webpack. Plugins are used for a wide range of tasks that the loaders cannot perform. They are most widely used for bundle optimization, minification, script injection, stats emission, etc.

Read more about the most common plugins in the webpack community — https://webpack.js.org/plugins/

Mode (new in Webpack 4)

Modes are introduced in Webpack 4. Modes are crucial to the new zero config approach. You can set the mode to either development or production.

Setting the mode to production enables webpack’s built-in optimizations that produce a good enough production build for most common use cases.

development mode runs with a default plugin NamedModulesPlugin activated. This plugin causes the relative path of the modules to be added to the emitted bundle. It is pretty helpful for debugging purposes during development.

production mode runs with three plugins — UglifyJsPlugin (minification of the output bundle), ModuleConcatenationPlugin (scope-hoisting for faster execution) and NoEmitOnErrorsPlugin (skips emitting bundle if there are errors while compiling).

Getting Started with Zero Config

We will bootstrap the most basic webpack config possible by leveraging webpack 4 modes.

Let’s start by creating a new directory and moving into it

mkdir webpack-modes && cd $_

Then, initialize a package.json

npm init -y

We will then install webpack and webpack-cli

npm i -D webpack webpack-cli

If you remember from our Core Concepts section, webpack 4 takes ./src/index.js as the default entry point. So, fire up your favourite code editor and create an index.js file in the src folder of your project’s root directory.

To keep it simple my ./src/index.js includes only 1 line of code —

console.log('Webpack Zero Config Works!');

Now, go ahead and add npm scripts for webpack —

scripts: {

"build": "webpack --mode production",

"dev": "webpack --mode development"

}

You will be able to see the difference between the size of the emitted main.js bundle of each mode.

development mode bundle is 2.83 kb while production mode bundle is just 564 bytes. Thanks to out-of-the-box optimization with Webpack 4.

Webpack Setup for Modern JavaScript

In the setup above, we do not do much. We bundle the JavaScript we write and that's it. We don't use any of the advanced features.

We will now use a config file to setup babel-loader to transpile our ES6+ code and html-webpack-plugin to simplify serving our webpack output bundle as a script tag on our HTML file.

First, let's add some more JavaScript code -

import someImportedFunction from './someFunction.js';


const testTranspile = () => console.log('I am an ES6 arrow function');


someImportedFunction();

testTranspile();

Next, we fetch the new dependencies -

npm i -D babel-core babel-preset-env babel-loader

babel-core and babel-preset-env to get babel setup ready to transpile ES6+ to ES5. Secondly, babel-loader enables us to use babel with webpack to transpile any .js file.

Then, we install the plugin we need -

npm i -D html-webpack-plugin

Now, your package.json should look something like this

{

"name": "webpack-modes",

"version": "1.0.0",

"description": "",

"main": "index.js",

"scripts": {

"build": "webpack --mode production",

"dev": "webpack --mode development"

},

"keywords": [],

"author": "",

"license": "ISC",

"devDependencies": {

"babel-core": "^6.26.0",

"babel-loader": "^7.1.4",

"babel-preset-env": "^1.6.1",

"html-webpack-plugin": "^3.1.0",

"webpack": "^4.2.0",

"webpack-cli": "^2.0.12"

}

}

Now add .babelrc file to your project's root directory to configure babel. To know more about babel presets and plugins - https://babeljs.io/docs/plugins/

{

"presets": ["env"]

}

Add an HTML file as template for the HtmlWebpackPlugin in public directory -

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>Webpack 4 Intro</title>

</head>

<body>

<!-- emitted bundle script will be added here -->

</body>

</html>

Last but not the least, we setup our webpack.config.js file. This is where we tell webpack to use babel to transpile our js files and attach it to the HTML template we created under the public directory.

Create webpack.config.js in the root directory of the project.

/*

the plugin that will generate the HTML5 file

with the emitted output bundle as a script tag

*/


const HtmlWebpackPlugin = require('html-webpack-plugin');


// importing node path module

const path = require('path');


module.exports = {

// this is where you can override the default entry point

entry: './src/index.js',

// this is where you can override the default output location

output: {

path: path.resolve(__dirname, './build'),

filename: 'bundle.js',

},


// this is how loaders are used

module: {

rules: [{

// regex to run the loader on all files ending with .js only

test: /\.js$/,

// we do not want to run the loader on node_modules contents

exclude: /node_modules/,


use: {

// specifying to use babel-loader

loader: 'babel-loader',

},

}],

},

// this is how plugins are used

plugins: [

new HtmlWebpackPlugin({

// the HTML5 template to use

template: './public/index.html',

// the emitted html file name

filename: './index.html',

}),

],

};

If we run our npm scripts again, The production bundle is again way smaller due to optimizations and minification.

If you check the bundle.js from any of the build (I recommend checking development bundle output because it will be more readable). You will see that both the modules we wrote are in the bundle and the ES6 arrow functions are transpiled down to normal functions.

You can play around with the example if you want. The source code is at - https://github.com/drenther/webpack-4-modes

Conclusion

Webpack is an extremely powerful tool and everyone should give it a try. Some of the best resources to dive deeper are -

The Official Documentation

Webpack Medium Publication

Webpack Academy