Getting Started
Webpack is a good fit when your application needs a customizable build pipeline: bundling JavaScript modules, processing assets, integrating loaders and plugins, and shaping output for different environments. For a very small page with one or two scripts, a bundler may be unnecessary at first; for an application with shared dependencies, npm packages, assets, and production builds, webpack gives you explicit control over how everything is assembled.
Webpack is used to efficiently compile JavaScript modules. Once installed, you can interact with webpack either from its CLI or API. If you're still new to webpack, please read through the core concepts and this comparison to learn why you might use it over the other tools that are out in the community.
Quick Start (Minimal Working Example)
If you want to get a working webpack project up and running quickly, the easiest way is to scaffold one using create-webpack-app.
npx create-webpack-app webpack-demo
cd webpack-demoBasic Setup
First let's create a directory, initialize npm, install webpack locally, and install the webpack-cli (the tool used to run webpack on the command line):
# Run the commands for one package manager only.
mkdir webpack-demo
cd webpack-demo
# npm
npm init -y
npm install webpack webpack-cli --save-dev
# yarn
yarn init -y
yarn add webpack webpack-cli --dev
# pnpm
pnpm init
pnpm add webpack webpack-cli -DThroughout the Guides we will use diff blocks to show you what changes we're making to directories, files, and code. For instance:
+ this is a new line you shall copy into your code
- and this is a line to be removed from your code
and this is a line not to touch.Now we'll create the following directory structure, files and their contents:
project
webpack-demo
├── package.json
├── package-lock.json
+ ├── index.html
+ └── src/
+ └── index.jssrc/index.js
function component() {
const element = document.createElement("div");
// Lodash, currently included via a script, is required for this line to work
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
}
document.body.appendChild(component());index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
<script src="https://unpkg.com/lodash@4.17.21"></script>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>We also need to adjust our package.json file in order to make sure we mark our package as private, as well as removing the main entry. This is to prevent an accidental publish of your code.
We also add "type": "module" so that Node.js treats .js files in this project as ES modules. That setting applies project-wide, including future Node.js scripts and webpack configuration files. If you would rather keep Node's default CommonJS behavior, omit "type": "module" and write the configuration later in this guide with require(...) and module.exports instead of import and export default.
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
- "main": "index.js",
+ "private": true,
+ "type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0"
}
}In this example, there are implicit dependencies between the <script> tags. Our index.js file depends on lodash being included in the page before it runs. This creates an implicit dependency on a global variable (_), making script execution order critical and harder to maintain.
There are problems with managing JavaScript projects this way:
- It is not immediately apparent that the script depends on an external library.
- If a dependency is missing, or included in the wrong order, the application will not function properly.
- If a dependency is included but not used, the browser will be forced to download unnecessary code.
Webpack solves these issues by explicitly declaring dependencies and bundling them together. This removes reliance on global variables and ensures scripts are executed in the correct order.
Creating a Bundle
First we'll tweak our directory structure slightly, separating the "source" code (./src) from our "distribution" code (./dist). The "source" code is the code that we'll write and edit. The "distribution" code is the minimized and optimized output of our build process that will eventually be loaded in the browser. Tweak the directory structure as follows:
project
webpack-demo
├── package.json
├── package-lock.json
+ ├── /dist
+ │ └── index.html
- ├── index.html
└── /src
└── index.jsThe dist directory is build output, so you usually do not hand-edit files there in a mature project. We are moving index.html into dist for now only as temporary scaffolding, so the browser has an HTML file that loads the first generated bundle. Later on in another guide, we will generate index.html rather than edit it manually. Once this is done, it should be safe to empty the dist directory and regenerate all the files within it.
To bundle the lodash dependency with index.js, we'll need to install the library locally:
# Run the command for one package manager only.
# npm
npm install lodash
# yarn
yarn add lodash
# pnpm
pnpm add lodashNow, let's import lodash in our script:
src/index.js
+import _ from 'lodash';
+
function component() {
const element = document.createElement('div');
- // Lodash, currently included via a script, is required for this line to work
+ // Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());Now, since we'll be bundling our scripts, we have to update our index.html file. Let's remove the lodash <script>, as we now import it, and modify the other <script> tag to load the bundle, instead of the raw ./src file:
dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
- <script src="https://unpkg.com/lodash@4.17.21"></script>
</head>
<body>
- <script src="./src/index.js"></script>
+ <script src="main.js"></script>
</body>
</html>In this setup, index.js explicitly requires lodash to be present, and binds it as _ (no global scope pollution). By stating what dependencies a module needs, webpack can use this information to build a dependency graph. It then uses the graph to generate an optimized bundle where scripts will be executed in the correct order.
With that said, let's run npx webpack from the project root. If webpack is installed locally, npx will run the local binary from node_modules/.bin; otherwise, it may download and execute it. This command takes our script at src/index.js as the entry point and generates dist/main.js as the output.
# Run the command for one package manager only.
# npm
npx webpack
# yarn
yarn webpack
# pnpm
pnpm exec webpack
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1851 msOpen index.html from the dist directory in your browser and, if everything went right, you should see the following text: 'Hello webpack'.
Modules
The import and export statements have been standardized in ES2015. They are supported in most browsers at this moment, however there are some browsers that don't recognize the new syntax. But don't worry, webpack does support them out of the box.
Behind the scenes, webpack analyzes your module graph and bundles the modules into code that the browser can load in the right order. It handles module syntax such as import and export, and supports various other module syntaxes as well. See Module API for more information.
Note that webpack will not alter any code other than import and export statements. If you are using other ES2015 features, make sure to use a transpiler such as Babel via webpack's loader system.
Using a Configuration
As of version 4, webpack doesn't require any configuration, but most projects will need a more complex setup, which is why webpack supports a configuration file. This is much more efficient than having to manually type in a lot of commands in the terminal, so let's create one:
Webpack configuration files can be written using either CommonJS or ECMAScript modules. The examples below use modern ESM syntax.
project
webpack-demo
├── package.json
├── package-lock.json
+ ├── webpack.config.js
├── /dist
│ └── index.html
└── /src
└── index.jswebpack.config.js
import path from "node:path";
import { fileURLToPath } from "node:url";
// In Node.js versions prior to native support for import.meta.dirname,
// derive __dirname from import.meta.url.
// (Node 20.11+ supports import.meta.dirname and import.meta.filename.)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
};Now, let's run the build again but instead using our new configuration file:
# Run the command for one package manager only.
# npm
npx webpack --config webpack.config.js
# yarn
yarn webpack --config webpack.config.js
# pnpm
pnpm exec webpack --config webpack.config.js
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1934 msA configuration file allows far more flexibility than CLI usage. We can specify loader rules, plugins, resolve options and many other enhancements this way. See the configuration documentation to learn more.
NPM Scripts
Given it's not particularly fun to run a local copy of webpack from the CLI, we can set up a little shortcut. Let's adjust our package.json by adding an npm script:
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0"
},
"dependencies": {
"lodash": "^4.17.21"
}
}Now the npm run build command can be used in place of the npx command we used earlier. Note that within scripts we can reference locally installed npm packages by name the same way we did with npx. This convention is the standard in most npm-based projects because it allows all contributors to use the same set of common scripts.
Now run the following command and see if your script alias works:
# Run the command for one package manager only.
# npm
npm run build
# yarn
yarn build
# pnpm
pnpm run build
...
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1940 msConclusion
Now that you have a basic build together, you should move on to the next guide Asset Management to learn how to manage assets like images and fonts with webpack. At this point, your project should look like this:
project
webpack-demo
├── package.json
├── package-lock.json
├── webpack.config.js
├── /dist
│ ├── main.js
│ └── index.html
├── /src
│ └── index.js
└── /node_modulesIf you want to learn more about webpack's design, you can check out the basic concepts and configuration pages. Furthermore, the API section digs into the various interfaces webpack offers.



