Javascript module bundler: Webpack (Essential to learn)

Biswasindhu Mandal
13 min readFeb 10, 2023

--

source: webpack

Here we learn how to use webpack in UI application

📚What is webpack?

  • Webpack is a free and open-source module bundler for JavaScript.
  • It is made primarily for JavaScript, but it can transform front-end assets such as HTML, CSS, and images if the corresponding loaders are included.
  • Webpack takes modules with dependencies and generates static assets representing those modules.

📚How to create a web project with webpack📚

1. Create a basic environment:

  • Create Project Directory
    mkdir webpackApp && cd webpackApp
  • install package.json
    npm init -y

2. Add Webpack dependencies into the project

  • Difference between dependencies & dev-dependencies in Node.js:
    - Dependencies are the packages that your project needs to run properly in production.
    - Dev-dependencies are the packages that are needed for development and building the project, but not required for it to run in production.
  • install dependencies: webpack& webpack-cli
    npm i webpack webpack-cli -save
    So, in your package.json it’s added like:
"dependencies": {
"webpack": "***",
"webpack-cli": "***"
},
  • change script in package.json to build the project
"scripts": {
"build": "webpack"
},

3. Create project structure for webpack

  • Application basic structure:
webpackApp

├───dist
│ ├───index.html
│ └───main.js (auto create after build)

├───node_modules

├───src
| └───index.js
|
├───package-lock.json
└───package.json
  • Create two directories: dist & src
  • Createindex.html within dist repo.
<!DOCTYPE html>
<html lang="eng">
<head>
<title>webpack</title>
</head>
<body>
<div style="text-align:center" id="main"></div>
<script src="main.js"></script>
</body>
</html>
  • Create index.js under src repo.
function mainContaint() {
var el = document.createElement("h1");
el.textContent = "This is First webpack Project";
return el;
}

document.getElementById("main").appendChild(mainContaint());
  • Now run the project:
    npm run build
  • So, wepack build the default script src/index.js & store build files under dist folder name as: main.js
  • Now I explain how to add more files.
webpackApp

├───dist
│ ├───index.html
│ └───main.js (auto create after build)

├───node_modules

├───src
│ ├───index.js
| └───module.js (add a new file)
|
├───package-lock.json
└───package.json
  • Now create another file under src repo as module.js.We are trying to import something into index.js and let's check what will happen…
  • Add this code within module.js file
export function module() {
var el = document.createElement("h2");
el.textContent = "This is Module Page";
return el;
}
  • Now import module.js into index.js file and update index.js as follows:
import { module } from "./module";

function mainBody() {
var el = document.createElement("h1");
el.textContent = "This is First webpack Project";
return el;
}

function main() {
var d = document.getElementById("main");
d.appendChild(mainBody());
d.appendChild(module());
}

(function () {
main();
})();
  • Now run the project: npm run build
  • Now you understand how to build your project using webpack.
  • If you are using visual code then you may run your project with “live-server”. Otherwise, you directly open dist/index.html file locally and after build refresh the browser.
  • So, you will add multiple files in this way and create UI according to that.

4. Describe “npm run build” in details

  • The build: "webpack" line in your package.json file specifies a script that runs Webpack to build your application. We know, webpack is a module bundler for JavaScript applications, which means it takes the application's code and its dependencies, and packages them into a single bundle (or several bundles) that can be efficiently loaded in a browser.
  • When we run npm run build, the webpack script specified in package.json will be executed, which will build the application using Webpack. The exact functionality of this script will depend on how it's configured, but typically it will:
    - Transpile code from modern JavaScript syntax to syntax that can be run in older browsers.
    - Bundle your code and its dependencies into a single file or a set of files.
    - Minimize and optimize our code for faster loading times in a browser.
    - Output the bundled code to a directory that can be served by a web server, such as dist directory.

📚webpack configuration📚

There are three(3) to configure webpack. These are called webpack mode.
1. none mode
2. production mode
3. development mode
Now we have to create a webpack configuration file: webpack.config.js and have to add to webpack configuration mode.

1. webpack configuration mode: none

  • none mode (webpack.config.js) will define as:
module.exports = {
mode: "none"
}
  • after build the code, output(dist/main.js) show as:

2. webpack configuration mode: production

  • production mode (webpack.config.js) will define as:
module.exports = {
mode: "production"
}
  • after build the code, output(dist/main.js) show as:

3. webpack configuration mode: development

  • development mode (webpack.config.js) will define as:
module.exports = {
mode: "development"
}
  • after build the code, output(dist/main.js) show as:
  • Here I write the hello world program and build the code with all mode
  • In development mode it’s contains lots of webpack comments.
  • In production mode don’t show extra code like development or none mode

📚Custom webpack configuration📚

  • If you create a custom webpack config file. Then create a file like: webpack_custom.config.js.
  • Define the webpack mode there, as follows:
module.exports = {
mode: "production" // define add 'production' mode
}
  • mention the custom file in your script.
"scripts": {
"build": "webpack --config webpack_custom.config.js"
},
  • Now you build your code and check the output (dist/main.js) file

📚Build webpack “devServer” or “server”📚

Still, now we are using either vs-code liver-server or run it locally.
In this block, we are going to learn how to create a server using webpack.

1. Add ‘webpack server’

  • Install ‘webpack server’: npm i webpack-dev-server --save-dev
  • So, in package.json added the devDependencies section as follows:
"devDependencies": {
"webpack-dev-server": "***"
}
  • Add server start command in package.json script
"scripts": {
"build": "webpack",
"server": "webpack-dev-server --open"
}
  • add devServer configuration at webpack.config.js
const path = require('path');

module.exports = {
devServer: {
// as default output directory is 'dist'
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8008
}
}

** In current webpack contentBase is not working, so use static as follows:

const path = require('path');

module.exports = {
devServer: {
// as default output directory is 'dist'
static: path.join(__dirname, 'dist'),
compress: true,
port: 8008
}
}
---------------------------------
OR
---------------------------------
module.exports = {
devServer: {
// as default output directory is 'dist'
static: {
directory: path.join(__dirname, 'dist')
},
compress: true,
port: 8008
}
}
  • Now build & run your server.
    build: npm run build
    run devServer: npm run server
  • So, when you hit the url: http://localhost:8008, you see it’s throwing an error like:

So, it clearly mentions that we need to define the webpack config mode: productionor development

  • There are two ways we define the mode
    1. package.json changes the server script to: webpack-dev-server --mode development --open
    2. Mention mode within wepback.config.js as: mode: "development"
  • Now run the server script(npm run server) and see it’s working fine.

📚Rename entries & output file📚

  • So, we learn how to configure webpack, custom webpack, webpack mode, devServer. Now we are returning to our previous application structure. In this section, I am going to change the input/output directory & file name and learn how to configure those through webpack configuration.
    This is our current code structure:
webpackApp

├───dist (default output directory)
│ ├───index.html
│ └───main.js (default output file)

├───node_modules

├───src
│ ├───index.js (default source/entry file)
| └───module.js
|
├───package-lock.json
├───package.json
└───webpack.config.js (default webpack cofig file)
  • Now we are trying to change this file or directory name
    Let's consider I am going to update files/directory as:
    — changes entry file name:
    src/index.jssrc/app.js
    — Changes output directory and file name:
    distpublic
    dist/main.jspublic/script.js
  1. Change default entries configuration:
  • Rename src/index.js name to src/app.js.
  • Now mention entry fileconfiguration as follows:
module.exports = {
// * * *
entry: "./src/app.js",
// * * *
}
  • Now clear the output file under dist directory and build again.

2. Change default output configuration:

  • Changes dist name to public and delete the output file if it exits in public directory.
  • Update src/index.html script file name from main.js to script.js
  • Now mention output directory & file configuration as follows:
const path = require('path');

module.exports = {
// * * *
// loader
output: {
path: path.resolve(__dirname, 'public'),
filename: 'script.js'
},
// * * *
}
  • This is current webpack.config.js as follows:
const path = require('path');

module.exports = {
mode: "production", // build type
entry: "./src/app.js", // entry point
output: { // output config
path: path.resolve(__dirname, 'public'), // output directory
filename: 'script.js' // output file
},
devServer: { // config devServer with current output file 'public'
static: path.join(__dirname, 'public'),
compress: true,
port: 8008
}
}
  • Now build again and see the output (public/srcipt.js).
  • Therefore, the current code structure
webpackApp

├───public (output directory)
│ ├───index.html
│ └───script.js (default output file)

├───node_modules

├───src
│ ├───app.js (entry file)
| └───module.js
|
├───package-lock.json
├───package.json
└───webpack.config.js (default webpack cofig file)

📚CSS & Style Loadder📚

Now html & script are loaded. But how to add image or css files.

1. Add CSS style Module

  • add style dependencey in package.json
    npm i style-loader css-loader --save-dev
  • add webpack configuration:
var path = require('path');

module.exports = {
// * * *
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
}
  • Create two directory styles and images under src directory
    add some image under images directory.
    crate a css file as: style.css and add this code there
/* src/styles/style.css */
body {
background-color: aqua;
background-image: url('../images/bg.avif'); /* background image */
}

.cl1 {
color: red;
font-size: 100px;
}
.cl2 {
color: pink;
font-size: 60px;
}

#my_logo {
content: url('../images/logo.png'); /* use some custom image */
width: 200px;
height: 200px;
padding: 20px;
}
  • import css file in app.js and update app.js as
// src/app.js
import { module } from "./module";
import './styles/style.css';

function mainBody() {
var el = document.createElement("h1");
el.className = "cl1";
el.textContent = "This is First webpack Project";
return el;
}

function main() {
var d = document.getElementById("main");
d.appendChild(mainBody());
d.appendChild(module());
}

(function () {
main();
})();
  • update module.js as follows:
// src/module.js
function addImage() {
var x = document.createElement("img");
x.id = "my_logo";
// x.setAttribute("src", "../images/logo.png");
// x.setAttribute("width", "200px");
// x.setAttribute("height", "200px");

var el = document.createElement("div");
el.appendChild(x);
return el;
}

export function module() {
var el = document.createElement("h2");
el.className = "cl2";
el.id = "id2";
el.textContent = "This is Module Page";
el.appendChild(addImage());
return el;
}
  • update package.json script:
  "scripts": {
"build": "webpack",
"server": "webpack-dev-server --open",
"start": "npm run build && npm run server"
},
  • Now, run the project: npm run start
  • Therefore, the current code structure
webpackApp

├───public (output directory)
│ ├───index.html
│ └───script.js (default output file)

├───node_modules

├───src
│ ├───images
│ │ ├───bg.avif
│ │ └───logo.png
│ │
│ ├───styles
│ │ └───style.css
│ │
│ ├───app.js (entry file)
| └───module.js
|
├───package-lock.json
├───package.json
└───webpack.config.js (default webpack cofig file)

📚Create Dev & Prod Environemnt📚

Mostly we know how to bundle the javascript project using webpack. In this section, we are learning about how to configure a development(dev) and production(prod) environment.
The development environment is your local computer, while the production environment is the live product customers or visitors might interact with your application.

1. Create ‘production’ and ‘development’ webpack configuration

  • Create two files: webpack.config.dev.js & webpack.config.prod.js.
  • Your current webpack.config.js as follows:
// webpack.config.js
const path = require('path');

module.exports = {
mode: "production", // build type
entry: "./src/app.js", // entry point
// Not required for development if you use default output format
output: { // output config
path: path.resolve(__dirname, 'public'), // output directory
filename: 'script.js' // output file
},
// Not required for production
devServer: { // config devServer with current output file 'public'
static: path.join(__dirname, 'public'),
compress: true,
port: 8008
},
// loader
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
}
  • Copy current webpack.config.js data to both files and delete it.
  • Now goto package.json and update the script as follows:
  "scripts": {
// 'prod' envs script
"build:prod": "webpack --config webpack.config.prod.js",
// 'dev' envs script
"build:dev": "webpack-dev-server --open --config webpack.config.dev.js"
},
  • For production not required the webpack devServer. So, for production, we only run the npm run build:prod (configure with custom webpack config file: webpack.config.prod.js.
  • For local development required the webpack devServer. So, we first build the code with npm run build:dev(configure with custom webpack config file: webpack.config.dev.js) and then we have to run the server: npm run server.

2. Configure Development Environment (webpack.config.dev.js)

If you are using the default output directory format then, output configuration not required.

  • Therefore, the development environment configuration with default output config is as follows:
// webpack.config.dev.js
const path = require('path');

module.exports = {
mode: "development",
entry: "./src/app.js",
/**
* As we are using default output directory (dist, dist/main.js)
* Then `output` config not required for development environment
*/
devServer: {
static: path.join(__dirname, 'dist'),
compress: true,
// if you don't mention port it will start with default port 8080
port: 8008
},
// loader
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
}
  • Now, development environment configuration with our custom output config as follows:
// webpack.config.dev.js
const path = require('path');

module.exports = {
mode: "development", // build type
entry: "./src/app.js", // entry point
/**
* `output` config must required for development environment
* Because we are using custom output config(public, public/script.js)
*/
output: { // output config
path: path.resolve(__dirname, 'public'), // output directory
filename: 'script.js' // output file
},
devServer: { // config devServer with current output file 'public'
static: path.join(__dirname, 'public'),
compress: true,
port: 8008
},
// loader
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
}
  • If you build your code with development environment script(npm run build:dev), then see no output file created in your output directory.

3. Configure Production Environment (webpack.config.prod.js)

For production build webpack devServer not required.

  • Therefore, the production environment configuration with default output config is as follows:
// webpack.config.prod.js
const path = require('path');

module.exports = {
mode: "production", // build type
entry: "./src/app.js", // entry point
output: { // output config
path: path.resolve(__dirname, 'public'), // output directory
filename: 'script.js' // output file
},
// loader
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
}
  • If you build your code with production environment script(npm run build:prod), then see output files created in your output directory, which is not happening with dev env script.
  • you may create two different files as index_dev.html & index_prod.html and run you code from two different custom output directory
  • Therefore, the current code structure
webpackApp

├───public (output directory)
│ └───index.html

├───node_modules

├───src
│ ├───images
│ │ ├───bg.avif
│ │ └───logo.png
│ │
│ ├───styles
│ │ └───style.css
│ │
│ ├───app.js (entry file)
| └───module.js
|
├───package-lock.json
├───package.json
├───webpack.config.dev.js (webpack dev envs cofig)
└───webpack.config.prod.js (webpack prod envs config)

📚Create a Standered Project using Webpack📚

The standard project should be like:

webpackApp

├─── build (build library)
│ ├───dev (Development build)
│ └───prod (Production build)

├───public
│ └───index.html

├───src (main project)
|
├───package.json
├───webpack.config.dev.js (webpack dev envs cofig)
└───webpack.config.prod.js (webpack prod envs config)

If we want to configure the above standard structure, then we need to move public/index.html to every build files. For this scenario we need to configure HtmlWebpackPlugin .

How to Configure HtmlWebpackPlugin ?

HtmlWebpackPlugin simplifies creation of HTML files to serve your webpack bundles.

  • install dependencies : npm install --save-dev html-webpack-plugin
  • Add HtmlPlugin in webpack config:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// * * *
// HtmlWebpackPlugin
plugins: [new HtmlWebpackPlugin({
template: "./public/index.html",
filename: "./index.html"
})]
// * * *
}

📚Uses of Webpack📚

Webpack is a popular module bundler for JavaScript applications. Here are some of the main uses for Webpack:

  1. Asset management: Webpack allows you to manage and organize all of the assets required for your project, such as JavaScript, CSS, images, and fonts files, into a single, optimized bundle.
  2. Module bundling: Webpack provides a way to bundle and organize your application’s code into smaller, more manageable modules that can be loaded on demand. This helps to improve the performance and scalability of your application.
  3. Code splitting: Webpack enables you to split your application’s code into smaller, independent chunks that can be loaded as needed. This can significantly improve the load time of your application and provide a better user experience.
  4. Transpilation: Webpack can transpile modern JavaScript code into backwards-compatible versions that can run in older browsers. This enables you to use the latest features of JavaScript in your projects while ensuring that your code will run in older browsers as well.
  5. Optimization: Webpack provides a variety of optimization techniques that can be applied to your project’s assets to reduce the size and improve the performance of your application.

These are some of the main uses for Webpack. It is a flexible and powerful tool that can be used for a wide range of projects, from simple static sites to complex, scalable web applications.

📚Example of a project that could be created using webpack📚

  1. A React-based front-end web application: Webpack can be used to bundle together all the components, dependencies, and assets required for a React-based front-end web application. This includes JavaScript, CSS, and images, among other things.
  2. A JavaScript library: Webpack can be used to create a standalone JavaScript library that can be used in other projects. The library can be composed of multiple files and dependencies, which webpack will compile and package into a single file for distribution.
  3. A Single Page Application (SPA): Webpack can be used to create a single-page application that dynamically updates content on a web page without requiring a full page reload. This can be useful for creating fast and responsive user interfaces.

These are just a few examples of projects that could be created using webpack. The exact implementation details would depend on the specific requirements of the project, but webpack provides a powerful and flexible platform for building and bundling complex web applications and libraries.

--

--

Biswasindhu Mandal

I am a Software Engineer, living in Kolkata, India. I love to work as a Javascript, Node.js Full Stack developer and OTT Frontend Developer.