Webpack is a web developer tool for bundling modules. It means webpack takes all the files of your project and turn it into a single file. With the rise of JavaScript as the language of the web and NodeJS that powers JS server, Webpack has been very popular and is used on almost every application. It can also be configured to support different types of assets such as images, fonts, and stylesheets. Since it’s release, Webpack has been improved to optimize performance and load times.
Webpack Setup
Webpack can be installed globally or locally for each project
It is recommended to install webpack locally, because then webpack can be updated per-project as needed. And if you ever want to use the latest webpack features for a new small project, you don’t have to update webpack of your other projects.
To install locally with npm
$ npm i webpack webpack-cli --save-dev
or if you prefer Yarn
$ yarn add webpack webpack-cli -D
Then add a webpack build command in package.json
file.
{
//...
"scripts": {
"build": "webpack"
}
}
Then run npm build
or yarn build
Configuration
Webpack can be run without providing any configuration file since version 4.0 with these rules as its default:
- Default entry point of your app is
./src/index.js
- Default output directory is
./dist/main.js
- Default mode is
production
Usually developers need their own configuration to better fit the project requirements. We can create a webpack.config.js
file in the root directory of the project and webpack will use it automatically. Some configuration we can make with webpack are as follows:
Entry point
Webpack will use the file mentioned the entry point to begin building internal dependency graph It will find out all the imports and collect them all. The default value is src/index.js
but you can change it to anything you want
module.exports = {
entry: './src/app.js'
}
Output directory
Output tells webpack where to emit the bundle of files it creates and what name to use. It defaults to ./dist/main.js
but you can change it into anything you want.
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'output'),
filename: 'bundle.js'
}
}
Mode
Webpack has production
and development
build mode which dictates how it process the files.
Development mode builds faster but less optimized. It also provides better debugging experience and more detailed error messages and warnings.
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'output'),
filename: 'bundle.js'
},
mode: 'development'
}
Loaders
Out of the box, webpack only understands JavaScript and JSON files. Loaders allow webpack to process other types of files and convert them into valid modules that can be consumed by your application and added to the dependency. Here is an example of loaders for .txt, .css or image types:
module.exports = {
entry: './src/app.js',
mode: 'development',
output: {
path: path.resolve(__dirname, 'output'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' },
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.(png|svg|jpg|gif)$/, use: 'file-loader' },
]
}
}
To learn more about loaders you can see the official documentation at https://webpack.js.org/guides/asset-management/
Plugins
Plugins are extensions that enhance the capability of webpack to do what loaders can’t do. For example, adding internationalization support or creating HTML files for serving the bundle file.
Let’s see an example of HtmlWebpackPlugin in action. First we have to install it
$ npm install --save-dev html-webpack-plugin
Then add it to the configuration
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
mode: 'development',
output: {
path: path.resolve(__dirname, 'output'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' },
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.(png|svg|jpg|gif)$/, use: 'file-loader' },
]
},
plugins: [new HtmlWebpackPlugin()]
}
Now when we run the webpack, it will create an HTML file in the dist
folder
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webpack App</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
Visit https://webpack.js.org/plugins/ for a list of useful webpack plugins.
Generate sourcemaps
Since webpack bundles the code, source maps are mandatory to get a reference to the original file that raised an error. For example, if you bundle three source files (a.js
, b.js
, and c.js
) into one bundle (bundle.js
) and one of the source files contains an error, the stack trace will simply point to bundle.js
. This is problematic as you probably want to know exactly if it’s a, b, or c file that is causing an error.
You can tell webpack to generate source maps using the devtool property of the configuration:
module.exports = {
entry: './src/app.js',
mode: 'development',
devtool: 'inline-source-map',
output: {
path: path.resolve(__dirname, 'output'),
filename: 'bundle.js'
}
}
Although it will cause slower build, it has no effect on production. Sourcemaps are only downloaded if you open the browser DevTools.
Watching changes and refresh
Webpack can be configured to automatically rebundle for any changes made in any of the resolved files by adding --watch
argument into the build script in package.json
file.
{
//...
"scripts": {
"build": "webpack --watch"
}
}
But of course the browser won’t be refreshed and still serving the same app. In order to make browser do a hard refresh after rebundle, you can use webpack-dev-server
$ npm install webpack-dev-server --save-dev
Then change the build script to use webpack-dev-server
{
//...
"scripts": {
"build": "webpack-dev-server --mode development"
}
}
WARNING: never use webpack-dev-server for production environment since you probably do not need watch and hard refresh on production. It’s also better to make scripts as verbose as possible by adding environment argument
{
//...
"scripts": {
"build": "webpack --mode production",
"dev" : "webpack-dev-server --mode development"
}
}
This way you can use npm dev
to enable watch and browser refresh, but still use the webpack production build by running npm build
.
There are even more configurations than these
I only covered configurations that are frequently used in a general JS project. Be sure to checkout webpack official guide at https://webpack.js.org/guides/ For more configs like code splitting, integrating Typescript and tree shaking.