Javascript module bundler: Webpack (Essential to learn)
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
- Create
index.html
withindist
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
undersrc
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 underdist
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 asmodule.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
intoindex.js
file and updateindex.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 yourpackage.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
, thewebpack
script specified inpackage.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 asdist
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 likedevelopment
ornone
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 thedevDependencies
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: production
or development
- There are two ways we define the mode
1.package.json
changes theserver
script to:webpack-dev-server --mode development --open
2. Mentionmode
withinwepback.config.js
as:mode: "development"
- Now run the server script(
npm run server
) and see it’s working fine.
- You may change it to
production
mode. - Need more details :👉 webpack devServer
📚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.js
→src/app.js
— Changes output directory and file name:
dist
→public
dist/main.js
→public/script.js
- Change default entries configuration:
- Rename
src/index.js
name tosrc/app.js
. - Now mention
entry file
configuration 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 topublic
and delete the output file if it exits inpublic
directory. - Update
src/index.html
script file name frommain.js
toscript.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
andimages
undersrc
directory
add some image underimages
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 updateapp.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 thewebpack devServer
. So, for production, we only run thenpm run build:prod
(configure with custom webpack config file:webpack.config.prod.js
. - For local
development
required thewebpack devServer
. So, we first build the code withnpm 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)
- check sample code 👉 webpackApp
📚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"
})]
// * * *
}
- Now create build for both dev & prod.
- More details check plugin documentation
- check sample code👉 WebpackApp_sample-code
📚Uses of Webpack📚
Webpack is a popular module bundler for JavaScript applications. Here are some of the main uses for Webpack:
- 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.
- 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.
- 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.
- 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.
- 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📚
- 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.
- 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.
- 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.