Complete Guide to Webpack: From Basics to Practical Usage
Introduction
Even if you work as a frontend engineer, Webpack might be one of those tools you don’t get to touch very often.
In most cases, it’s defined at the start of a project, so you don’t have many opportunities to deal with it frequently.
However, there are times when you’re forced to look at it, such as when upgrading package versions or when newly created code or assets (like images) in a new directory aren’t included in the build.
I myself recently upgraded from Webpack 4 to 5 and struggled quite a bit.
This article is meant to help you understand the basics of Webpack and prepare for the day when you’ll need that knowledge.
Official webpack site
Webpack is a convenient tool that can be used in many environments, and it’s difficult to cover everything in a single article. For environments using React and TypeScript, I introduce them in a separate article.
Goal of this article
We’ll write simple HTML, JavaScript, and CSS, bundle them with Webpack, and confirm that they display correctly in the browser.
We’ll add files one by one and check behavior with Webpack as we go, making this a tutorial that helps you get a feel for how to configure Webpack.
What is webpack?
webpack is a tool called a module bundler, mainly used to bundle JavaScript code and other resources (CSS, images, fonts, etc.) into a single bundle file.
This makes it possible to deliver web applications efficiently.
Specifically, Webpack does the following:
-
Module bundling
It bundles multiple JavaScript files into one large file or several smaller files (chunks). This reduces the number of resource requests and improves performance. -
Transpiling
It converts ES6+ code, TypeScript, and even JSX (used in React) into formats supported by browsers. -
Asset management
It can also process non-JavaScript resources such as images, fonts, and stylesheets. These may be converted into appropriate formats, and URLs can be automatically rewritten. -
Code splitting
It can output different parts of an application (such as per page) as separate files, so code that doesn’t need to be loaded initially can be loaded later on demand. -
Plugins and loaders
In Webpack, you can use plugins and loaders to customize how resources are processed and to optimize code. Loaders are used to transform files, while plugins extend the build process.
Starting webpack with the minimum setup
Let’s start using webpack right away and gradually get a feel for its strengths.
Create a directory called webpack-tutorial and initialize it as a Node.js project.
npm init
You’ll be asked several questions, but you can just keep pressing Enter.
Installing webpack
Install webpack with the following command:
npm i -D webpack webpack-cli
Since we’ll use it from the CLI, we also install webpack-cli.
Preparing sample code
Prepare sample JavaScript code as src/index.js.
function component(name) {
const element = document.createElement('div');
element.innerHTML = `Hello ${name}`
return element;
}
document.body.appendChild(component('World'));
Next, create an HTML file that loads this script and save it at the project root.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>webpack tutorial</title>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>
After creating it, open index.html in the browser and confirm that Hello World is displayed.
Bundling JavaScript files with webpack
Now that we have our sample code, let’s bundle it with webpack.
npx webpack
A new file is created as /dist/main.js.
Let’s check the file.
Before formatting
document.body.appendChild(function(){const e=document.createElement("div");return e.innerHTML="Hello World",e}());
After formatting
document.body.appendChild(
(function () {
const e = document.createElement('div');
return (e.innerHTML = 'Hello World'), e;
})()
);
Although the style differs from our sample code, it performs the same processing.
To make sure this code actually works, we’ll change the JS file loaded by the HTML and test it.
Change the save directory from the project root to /dist/index.html, and fix the JS file path.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>webpack tutorial</title>
</head>
<body>
- <script src="./src/index.js"></script>
+ <script src="./main.js"></script>
</body>
</html>
Check again in the browser.
Since Hello World is displayed, we’ve confirmed that the file bundled by webpack works correctly.
Up to this point, everything worked without any Webpack-specific configuration.
When using webpack on its own, the mechanism is actually not that difficult.
However, this alone isn’t enough for real-world use, so let’s dig into webpack a bit more.
Detecting file changes
webpack has a watch mode that detects file changes and automatically re-bundles.
npx webpack --watch
With this enabled, when you modify a JS file, it will be re-bundled and the changes will be reflected in the browser immediately.
- document.body.appendChild(component('World'));
+ document.body.appendChild(component('Test'));
Supporting older browsers
Babel is a JavaScript compiler (transpiler) used to convert modern JavaScript code into a form that works in older browsers.
It’s mainly used to transform code that uses modern JavaScript features into versions compatible with older browsers.
-
Transpiling (conversion)
- Converts new syntax and features from ES6+ (ECMAScript 2015 and later) to ES5 (the version supported by older browsers).
- Examples: converting const and let to var, converting arrow functions to regular functions.
-
Providing polyfills
- When new JavaScript features don’t work in older environments, Babel can add code to emulate those features via core-js or @babel/polyfill.
- Examples: Promise, Array.includes, etc.
-
Support for React and TypeScript
- Can convert JSX (the special syntax used in React) into regular JavaScript.
- Can also convert TypeScript code to JavaScript using Babel (though it does not perform type checking).
-
Plugins and presets
- Babel has an extensible system that lets you customize transformations via plugins and presets.
- Presets: Collections of plugins (e.g., @babel/preset-env).
- Plugins: Modules that handle specific transformations (e.g., @babel/plugin-transform-arrow-functions).
Official Babel site
In the code we used earlier, we used const, which is a feature supported from ES6 onward.
This causes problems in browsers that only support up to ES5.
So we’ll use Babel to convert the code to ES5.
Since we’ll still be bundling with webpack, we also need to integrate Babel with webpack.
Introducing Babel
Install Babel with the following command:
npm i -D @babel/core @babel/preset-env
@babel/preset-env is required for converting ES6 -> ES5.
Create a .babelrc file at the project root and specify the preset we just installed.
{
"presets": ["@babel/preset-env"]
}
Integrating with webpack
In webpack, we use programs called loaders to configure transformations.
We’ll use babel-loader as the loader that converts ES6 -> ES5, so install it.
npm i -D babel-loader
Configure the loader in the webpack config.
/** @type {import('webpack').Configuration} */
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
},
],
},
};
With this configuration, .js files will be transformed using babel-loader.
Checking Babel’s behavior
Now that the setup is complete, bundle with webpack.
npx webpack
This time, you’ll see that the output JS file is different from before.
const is no longer used.
(() => {
var e;
document.body.appendChild((((e = document.createElement('div')).innerHTML = 'Hello '.concat('Test')), e));
})();
We’ve confirmed that the JS file is generated in ES5 format, so it will now work in older browsers.
Bundling CSS
We’ve looked at bundling JS files and supporting older browsers.
Next, we’ll make it possible to handle CSS with webpack.
Installing loaders
When importing CSS in JavaScript code and applying it as an HTML <style> tag, you need two loaders:
-
css-loader
Makes Webpack recognize CSS files and include them in the bundle. -
style-loader
Inserts CSS into HTML as <style> tags.
npm i -D style-loader css-loader
Configuring loaders in webpack
Configure the two loaders to be used for .css files.
/** @type {import('webpack').Configuration} */
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
},
+ {
+ test: /\.css$/,
+ use: ["style-loader", "css-loader"],
+ },
],
},
};
When loaders are defined in an array, they are applied from the end of the array.
So they run in the order css-loader -> style-loader.
Preparing sample code
Create a CSS file at /src/styles.css.
body {
padding: 40px;
color: blue;
}
Import the CSS file in the JavaScript file.
+ import './styles.css'
Checking behavior
Now that the setup is complete, bundle with webpack.
npx webpack
When you check in the browser, the text is blue, confirming that the CSS is applied correctly.
Webpack modes
So far, a warning has been displayed when running webpack.
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.
The mode option has not been set, so Webpack will fall back to production for this value.
By setting the mode option to development or production, you can enable defaults appropriate for each environment.
Up to now, bundling has been done in production mode.
In webpack 5, there are three possible settings:
- development
- production
- none
Let’s try running webpack in development mode.
npx webpack --mode=development
If you look at /dist/main.js, you’ll see that it now contains comments.
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _styles_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./styles.css */ \"./src/styles.css\");\n\nfunction component(name) {\n var element = document.createElement('div');\n element.innerHTML = \"Hello \".concat(name);\n return element;\n}\ndocument.body.appendChild(component('Test'));\n\n//# sourceURL=webpack://webpack-tutorial/./src/index.js?");
From the comments, you can see that this is the bundled result of index.js.
Comments and other information that weren’t present in production mode are now included, which seems useful during development.
Conclusion
In this article, we’ve covered the basic usage and configuration of webpack.
Webpack is a very powerful and feature-rich tool, which can make its configuration feel a bit complex.
However, by learning it step by step, you can greatly improve both application performance and development efficiency.
Use the content introduced here as a reference to add the settings your own projects need, and make full use of webpack’s capabilities.
Recommended article
Here is an article on building a React + TypeScript environment with Webpack:
Questions about this article 📝
If you have any questions or feedback about the content, please feel free to contact us.Go to inquiry form





