Webpack Tutorial for Beginners

Photo by Rayia Soderberg on Unsplash
Photo by Rayia Soderberg on Unsplash
Webpack can bundle scripts, styles, images, and assets. It will analyze the dependencies between files and modules, and finally output static files.

Webpack can be used to bundle scripts, styles, images, and assets. During the bundle process, it will analyze the dependencies between files and modules, and finally output static files. These static files already contain third-party modules. In other words, there is no need to install third-party modules in runtime. Many SPA frameworks, such as React, Angular, Vue.js and React Native, all use Webpack.

Webpack
Webpack

The complete code can be found in .

Creating a Webpack Project

Create an NPM project.

% mkdir WebpackExample
% cd WebpackExample
WebpackExample % npm init -y

Install webpack and webpack-cli packages.

WebpackExample % npm install webpack webpack-cli --save-dev

Create the first JavaScript file called index.js where we will use Lodash module, so let’s install it.

WebpackExample % npm install --save lodash
WebpackExample % mkdir src
WebpackExample % cd src
WebpackExample/src % vi index.js

In index.js, we use lodash simply to print “Hello Webpack!”.

import _ from 'lodash';
console.log(_.join(['Hello', 'Webpack'], ' '));

Create a configuration file for Webpack. Its default file name is webpack.config.js. In this configuration file, the entry property is the entry file, and the output property is the output directory and file name.

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

The basic Webpack project is done. Let’s use Webpack command shown below to bundle src/. If the configuration file of webpack is not named as webpack.config.js, use –config to specify the path of the file.

WebpackExample% npx webpack
Hash: 4cdaba133dc7948617d8
Version: webpack 4.43.0
Time: 42ms
Built at: 07/06/2020 11:13:20 AM
   Asset       Size  Chunks             Chunk Names
index.js  959 bytes       0  [emitted]  main
Entrypoint main = index.js
[0] ./src/index.js 31 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

We can see a folded added called under the project. Under the folder, the file dist/index.js is the bundle file.

WebpackExample % ls dist
index.js

Take at look at dist/index.js. You can see that Lodash module is also compiled in it. Webpack bundles several JavaScript files into a single JavaScript file, and also minifies the bundle file.

Finally, let’s add npx webpack command to the NPM script. Modify package.json as follows:

{
  "name": "WebpackExample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12"
  }
}

After adding the NPM script, you can use npm run build command to bundle the project.

WebpackExample % npm run build

HtmlWebpackPlugin

The main purpose of Webpack is to bundle several JavaScript files into a single JavaScript file. Of course, it is far more than that. JavaScript is mainly used to develop web pages, so there must be HTML files. So Webpack can also help us output HTML files.

Install HtmlWebpackPlugin .

WebpackExample% npm install --save-dev html-webpack-plugin

Add an HTML template file.

WebpackExample % mkdir public
WebpackExample % cd public
WebpackExample/public % vi index.html

The HTML template file is as follows. It is a very simple HTML file, and Webpack will automatically add the compiled index.js to the template file.

<html>
<head>
</head>
<body>
<div id="app">
</div>
</body>
</html>

Modify src/index.js as follows:

import _ from 'lodash';
const app = document.getElementById('app');
app.innerHTML = _.join(['Hello', 'Webpack'], ' ');

In webpack.config.js, we add HtmlWebpackPlugin to the plugin list. The template is our HTML template file, filename is the name of the output file under dist/, and inject is whether to inject index.js into the HTML template file.

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
  ],
};

Let’s bundle the project!

WebpackExample% npm run build

Let’s look at dist/, you can see index.html is added. Open index.html with browsers, you can see it outputs “Hello Webpack”. Open and take a look at index.html, you can find that not only index.js is injected, but the entire file is also minified.

WebpackExample % ls dist
index.html index.js

CleanWebpackPlugin

Every time we bundle a project, it directly outputs to the dist folder and overwrites the existing files. It doesn’t clear the last output files, but just directly overwrites them. That turns out dist/ may contains some files from the last bundle but not existing in this bundle. We can use CleanWebpackPlugin to clear the last Bundle.

Install CleanWebpackPlugin.

WebpackExample% npm install --save-dev clean-webpack-plugin

Add CleanWebpackPlugin to webpack.config.js so that every time we bundle the project, the last bundle output will be cleared first.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'index.js,
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
    new CleanWebpackPlugin(),
  ],
};

Change Entry File

The entry in webpack.cofig.js can be a string or an object. When it is a string, its default name is index; when it is an object, we can set multiple entries and names.

Modify webpack.config.js as follows. Now there is an app under entry. On output, we can set the output file name according to the name of the entry.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
  ],
};

After bundling the project again, app.bundle.js will be added under dist/.

WebpackExample % npm run build
WebpackExample % ls dist
app.bundle.js index.html

CSS Loaders

Webpack handles js files by default, but it can handle other file types by adding loaders. Next, let’s make our project can handle CSS files.

Install style-loader and css-loader .

WebpackExample % npm install --save-dev css-loader style-loader

Create src/style.css file.

.hello {
  color: red;
}

In src/index.js, we can use import to import CSS files.

import _ from 'lodash';
import './style.css';

const app = document.getElementById('app');
app.innerHTML = _.join(['Hello', 'Webpack'], ' ');
app.classList.add('hello');

Finally, we have to set the CSS loader in webpack.config.js as follows. Add style-loader and css-loader to the rules, and specify the file types that the loader can handle.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
    new CleanWebpackPlugin(),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
        ],
      },
    ],
  },
};

Aftr bundling the project, you can found that there is no .css file in the dist/. This is because CSS is bundled into app.bundle.js.

File Loaders

With file-loader , Webpack can also handle image files. Next, let’s add a loader to process image files.

Install file-loader.

npm install --save-dev file-loader

Put an image file in src/, and name it as src/icon.png.

In src/index.js, you can use import to import image files.

import _ from 'lodash';
import './style.css';
import Icon from './icon.png';

const app = document.getElementById('app');
app.innerHTML = _.join(['Hello', 'Webpack'], ' ');
app.classList.add('hello');

const icon = new Image();
icon.src = Icon;
app.appendChild(icon);

Finally, in webpack.config.js, add file-loader and set the file types that can be processed.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
        ],
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader',
        ],
      },
    ],
  },
};

Bundle the project. You can a .png file added under dist/. The file name has been re-encoded.

WebpackExample % ls dist
99d4ae376af2a9084b5f65b2fc8b8156.png app.bundle.js                        index.html

HotReload/LiveReload

We will introduce powerful features of Webpack, that are Hot Reload and Live Reload. Both mean that when the project has any changes, it can immediately recompile and refresh the display on browsers. The difference is that Hot Reload only updates the changed parts, while Live Reload refreshes entirely. Many SPA frameworks support Hot/Live Reload. It is very easy to add this feature to Webpack projects.

Install webpack-dev-server .

npm install --save-dev webpack-dev-server

In webpack.config.js, we have added devtool and devServer. devtool can specify different source maps.

DevServer settings:

  • port: Specify the port number. The server url will be http://localhost:[port].
  • transportMode: refers to how browsers communicates with devServer. ws means to use WebSocket. The default is sockjs, that uses sockjs-node module. This is because some browsers do not support WebSocket.
  • hot/liveReload: Refers to use either Hot Reload or Live Reload.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js',
  },
  devtool: 'inline-source-map',
  devServer: {
    transportMode: 'ws',
    hot: false,
    liveReload: true,
    port: 9000,
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'Home',
      filename: 'index.html',
      template: 'public/index.html',
      inject: true,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
        ],
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader',
        ],
      },
    ],
  },
};

Add the command to start devServer in package.json. --open is to let Webpack automatically open the browser for us and browse directly to http://localhost:[port].

{
  "name": "WebpackExample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "start": "webpack-dev-server --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^3.6.0",
    "file-loader": "^6.0.0",
    "html-webpack-plugin": "^4.3.0",
    "style-loader": "^1.2.1",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "dependencies": {
    "lodash": "^4.17.15"
  }
}

Finally, let’s run devServer. Modifing the string of “Hello Webpack”, you can see it immediately refresh the screen!

WebpackExample % npm run start

TypeScript

Finally, if you want to use TypeScript to develop your project, you can refer to the following article, which explains how to add ts-loader.

Conclusion

Although we have introduced many features of Webpack. However, it has much more features than these, and this article can only give you a general idea of Webpack. With plugins and loaders, you can expand the functionality of Webpack, and you can also develop it yourself. Although we may not actually build our own Webpack project, if you are a web developer, you will definitely use React/Angular/Vue.js. They all use Webpack to bundle projects. Understanding Webpack can give us a better understanding of these frameworks.

Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like