× {{alert.msg}} Never ask again
Receive New Tutorials
GET IT FREE

Module Bundling with Webpack: Getting Started Guide

– {{showDate(postTime)}}

webpack

In the wake of React—Facebook’s UI library—came Webpack, a simple but awesome module bundler. Module bundlers are just what they are called, they bundle up JavaScript modules into one file. This way, when the client makes a request to your server, it doesn’t have to make multiple requests for static files. Instead, one file is requested, which in some cases, includes your JavaScript bundle and CSS style. This helps optimize load time and makes you more in control as you can choose to include only what you need when you need it.

Enough talk, let’s go over to a sample code and try out Webpack. A regular and simple HTML page that uses jQuery for its functionalities, like changing the color of a text in a paragraph, looks more like:

<!DOCTYPE html>
<html>
<head>
    <title>Simple Webpack Trial</title>
</head>
<body>
    <p> I am a text</p>
    <script type="text/javascript" src="src/jquery.js"></script>
    <script type="text/javascript" src="src/script.js"></script>
</body>
</html>

We include jQuery and our own custom script, which looks something like:

....
$("p").css({ color: 'red'});
....

This example looks fine because we don’t have many JavaScript files to handle and worry about. It is relatively easy for anyone to handle and modify—but it is not efficient. In a larger web application that depends on different mini JavaScript libraries, this method of handling our JavaScript files makes it harder to handle, scale and improve from the developers perspective. From the users perspective, it increases load time. I can go on about how module bundlers can improve a developers life, but we can stop here and go straight to learning how to implement Webpack.

Let’s Webpack it

Start off by making sure you have Node and NPM installed on your computer. Start with following commands:

# make project directory
$ mkdir cmwebpack

# go into directory
$ cd cmwebpack

# initiate node project
$ npm init

Fill out the prompts from the npm init command. Next, make your project directory look like so:

cmwepack
    |-- package.json
    |-- index.html
    |--src
        |- App.js

What’s left is to install Webpack globally using NPM and we are good to go.

npm install webpack -g

With the structure below, we can refactor our initial HTML and jQuery code. First, we can install jQuery using NPM:

npm install jquery --save-dev

After that, we can change our custom JavaScript (App.js) file to:

let $ = require('jquery');
$("p").css({ color: 'red'});

Now it’s time for Webpack. Open up the directory in a terminal and run:

webpack ./src/App.js ./build/bundle.js

A JavaScript bundle will be created in our build directory in the project folder. We can link our bundled JavaScript file in our HTML, like so:

<!DOCTYPE html>
<html>
....
<p> I am a text</p>
    <script type="text/javascript" src="build/bundle.js"></script>
</body>
</html>

When we view the HTML file, we should get the same result. This method encourages modular JavaScript and different JavaScript engineers can work on different aspects of the same project.

Now, let’s understand what the above Webpack command did. The first argument in the command is the path to our entry file that connects to the other JavaScript modules. The second argument is the path and file name for the bundled JavaScript.

Webpack Configuration

Just using Webpack from the command line limits its ability. Therefore, to be able to fully utilize Webpack, we can create a configuration file in the root of our project directory called webpack.config.js. Our config file is a JavaScript module that we can add specific details to improve our JavaScript bundle like minify our files or convert SASS to CSS and Jade to HTML using loaders and plugins (more on that later).

To get started, we can now install Webpack as a dev dependency in our project using NPM:

npm install webpack --save-dev

Next is to edit our config file. We can recreate our command from the command line:

webpack ./src/App.js ./build/bundle.js

to:

const path = require("path");
const config = require("./package.json");

module.exports = {
  entry: path.resolve(__dirname, config.main),  // entry file to all our js modules
  devtool: "source-map",  // add source mapping
  output: {
    path: __dirname,  // path to output files
    filename: '/build/bundle.js'
  }
}

Now we can run just webpack in the console from the project directory and our modules will be bundled up.

Tip

If you’re like me, you might have already gotten tired of running the Webpack command every single time you make a change to your JavaScript modules. You can watch for changes and automatically bundle your modules using:

webpack --watch

Development Server

The Webpack development server is there to help streamline workflow with Webpack. It already comes pre-bundled with hot module replacement with inline mode and all you need is to use the necessary CLI flags.

# install webpack-dev-server
$ npm i webpack-dev-server -D

# run webpack-dev-server
$ webpack-dev-server

When you run the Webpack dev server, it uses the Webpack configuration file in the root of the project folder for its configuration. You can specify a different configuration file by using the --config flag.

$ webpack-dev-server --config ./path/to/webpack.dev.js

To enable inline mode with hot module replacement, use:

$ webpack-dev-server --inline --hot --config ./path/to/webpack.dev.js

If the static document you want to serve is in another directory, you can tell the Webpack dev server using the --content-base flag like so:

$ webpack-dev-server --inline --hot --content-base ./path/to/index.html

Webpack Preloaders and Loaders

This is one of the most interesting features of Webpack. It allows you to preprocess files as they are loaded and since everything is a module in Webpack (yes PNG, Less, Jade, and CSS files are all modules) you can easily load them using specific Webpack loaders.

A sample use case would be when a group of four developers come together and decide to build a single web application, which is great, but they all have different backgrounds in CSS, Less, Babel, ES6, and CoffeeScript, respectively. Instead of learning a centralized concept which can take time, everyone can use whatever they feel comfortable working with and get work done. Everything can be loaded using Webpack loaders.

To use Webpack loaders, we can install the respective loaders from the webpack list of loaders.

For the above use case, we need to run the following commands:

# For css developer
$ npm i css-loader -D

# for less developer
$ npm i less-loader -D

# for both css and less developer
$ npm i style-loader -D

All we did in the above commands is to install the required loaders for the CSS and Less developer. To utilize this in our code, all we have to do is to require the modules using these loaders in our entry file. If your entry file is App.js, we require our file like so:

// for css developer
require('style!css!./css-style.css');

// for less developer
require('style!css!less!./less-style.less');

The code above may look a bit confusing but what happens is:

  • For the CSS developer, the CSS file is run through the CSS loader and the result is run through the style loader, which then wraps the result in an HTML <style> tag and appends it to the DOM.
  • For the Less developer, it follows a similar process. The Less file is run through the Less loader and the result is run through the CSS loader then through the style loader.

That method is called chaining loaders.

Instead of appending the loaders to every file that’s required for our app, a much better way is to include the loaders in the module loaders array in our Webpack config file. To add it, we add a module key to our exports object:

module.exports = {
    .....,
  module: {
    loaders: [
    // for css files
      { test: /\.css$/,
          exclude: /(node_modules|bower_components)/,
          loader: ["style", "css"]
      },
      // for less files
      { test: /\.less$/,
          exclude: /(node_modules|bower_components)/,
          loader: ["style", "css", "less"]
      }
    ]
  }
}

So, what we do in our loaders array is to add an object that tests a given file extension — in this case, files ending with .css — exclude our nodemodules and bowercomponents directories and use the loaders’ CSS and style.

Now our entry file can just require those files. And whenever Webpack runs, the loaders are automatically matched to the files.

require("./css-style.css");
require("./less-style.less");

Following these given steps, we can do the same for our ES6 and CoffeeScript files:

# install babel es6 loader
$ npm i babel-loader babel-core babel-preset-es2015 -D

# install coffeescript loader
$ npm i coffee-loader -D

Setup these loaders in our Webpack config file:

loaders: [
      // css and less loaders
      // .......
      { test: /\.js$/,
          exclude: /(node_modules|bower_components)/,
          loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      },
      { test: /\.coffee$/,
          exclude: /(node_modules|bower_components)/,
          loader: 'coffee-loader'
      }
    ]

And we are good to go, everyone can now contribute.

Webpack preloaders are executed first before the loaders. This is a way to run the source files through a given loader without changing it before our main loaders run—an example would be source file linting.So, assuming we have an

So, assuming we have an eslint setup, this is how to lint our ES6 files:

# install eslint-loader
$ npm i eslint-loader -D

Add configuration to our Webpack config file:

module.exports = {
    .....,
  module: {
      preLoaders: [
      { test: /\.js?$/, exclude: /node_modules/, loader: 'eslint-loader', include: __dirname + '/' }
    ],
    loaders: [
      //...
      // our loaders
    ]
  }
}

And we are good to go.

Webpack Plugins

Since loaders add flavor to your Webpack usage, plugins do a lot more than optimize it. Unlike loaders, each Webpack plugin has a specific usage.

We will talk about my two most utilized plugins.

UglifyJsPlugin

This helps minify and uglify your JavaScript module after bundling and it is shipped with the Webpack module.

To add it, require Webpack in your config file and specify it in the plugins array:

const webpack = require("webpack");
const path = require("path");
const config = require("./package.json");

module.exports = {
  //entry,
  //output,
  //modules,
  //......,
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
    compress: {
        warnings: false
      }
    })
}

extract text plugin

It is easy to bundle your CSS output and JavaScript together. There is a better way to use the extract text plugin. As the name implies, it extracts a given code after the loaders, and it then creates a separate file for it.

To use, first, install:

# install extract text plugin
$ npm i extract-text-webpack-plugin -D

Require in our configuration file:

const ExtractTextPlugin = require("extract-text-webpack-plugin");

Add to a specific loader, in this case, the Less file loader that we added earlier:

module.exports = {
    .....,
  module: {
    loaders: [
      // for less files
      { test: /\.less$/,
        exclude: /(node_modules|bower_components)/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader", "less-loader")
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("style.css")
  ]
}

Don’t forget to add an instance to the plugins array and you’re good to go.

Now you can go forth and Webpack your modules!

Other tutorials you might be interested in:


Author’s Bio

Chimeremeze Ukah is a web developer with years of experience in designing and developing user interfaces, testing, debugging, and training staff on web application usage. He has proven his ability in optimizing web functionality that improve data retrieval and workflow efficiencies.



Author
Chimeremeze Ukah
Chimeremeze Ukah
5.0
Full Stack Engineer
Web Developer with 8 years of experience in designing and developing user interfaces, testing, debugging, and training staffs on web application usage. Proven ability in optimizing web...
Hire the Author

Questions about this tutorial?  Get Live 1:1 help from JavaScript experts!
K M Rakibul Islam
K M Rakibul Islam
5.0
★Top Ruby on Rails Mentor since January 2016 (99 months in a row!)★
Experienced (15+ years) developer and friendly Ruby on Rails and React/Next.js/Redux Developer/Mentor (with passion for helping others learn) | ★...
Hire this Expert
Yuriy Linnyk
Yuriy Linnyk
5.0
Webdev Coach • 18yr+ Javascript Developer • 5yr+ CodeMentor.
You can understand it! Whether you're catching up in a coding bootcamp, or nailing a bug — reach me in the chat and we'll figure it out. I know you...
Hire this Expert
comments powered by Disqus