At its core, webpack is a static module bundler
for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph from one or more entry points and then combines every module your project needs into one or more bundles, which are static assets to serve your content from.
- To run webpack:
npx webpack
. This will generate amain.js
file underdist
folder. - To se more options:
npx webpack --stats detailed
Refers to various kinds of images, fonts or plain text files.
asset/resource
- will duplicate the asset or image intodist
folder and reference as path directoryasset/inline
- asset in line module, asset or image is injected into JS bundle as the data URI (base 64) and inject it directly into the main JS bundleasset
- webpack will decide if the asset is aasset/resource
(if asset size > 8kB) orasset/inline
(if asset size < 8kB) based on image size, can be configured.asset/source
- import a text file into image src
We can modify the size:
module: {
rules: [
{
test: /\.(png|jpg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 3 * 1024, // 3 kilobytes
},
},
},
{
test: /\.txt/,
type: 'asset/source',
},
],
},
- 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 graph.
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
//webpack will read the loader from right to left
use: ['style-loader', 'css-loader', 'sass-loader'],
},
- javascript compiler
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/env'],
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
},
After npm run build
, we will see style.css
being created and we need to reference this in our html <link rel="stylesheet" href="./dist/styles.css" />
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.css',
}),
],
browser location
: if the file didnt change between page reloads, your browser can save it ascache
, so it does not need to download again- however, we need a mechanism to update the cache if not browser will keep fetching the outdate cache
- we can use add a
MD5 hash
to the filename examplebundle.[contenthash].js
orstyles.[contenthash].css
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, './dist'),
publicPath: 'dist/',
},
- new bundles are created everytime the code gets updated and build
- we can use a webpack plugin to maintain it
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*',
path.join(process.cwd(), 'build/**/*'),
],
}),
],
};
- Alternatively we can use default
clean
method - if we set
dry:true
, webpack will inform you which files it is going to remove instead of actually removing them keep
tells webpack which file to keep
output: {
filename: 'bundle.[contenthash]js',
path: path.resolve(__dirname, './dist'),
publicPath: 'dist/',
clean: {
dry: true,
keep: /\.css/
},
},
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*',
path.join(process.cwd(), 'build/**/*'),
],
}),
],
};
- create own template for generating HTML files
- There are plenty of template engines such as
ejs
,handlebars
etc - using
handlebars
{
test: /\.hbs$/,
use: ['handlebars-loader'],
},
- differentiate prod and dev config
- add a devServer from
webpack-dev-server
- change script command in package.json
hot
in dev enables hot module replacement, a great feature supported out of the box
"build": "webpack --config webpack.production.config.js",
"dev": "webpack serve --config webpack.dev.config.js --hot"
module.exports = {
mode: 'development',
devServer: {
port: 9000,
static: {
directory: path.resolve(__dirname, './dist'),
},
devMiddleware: {
index: 'index.html',
writeToDisk: true,
},
},
};
- splitting into more bundles
- update the entry in the webpack config
- and also the filename, use [name] so it will take the entry point as the name
module.exports = {
entry: {
'hello-world': './src/hello-world.js',
kiwi: './src/kiwi.js',
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, './dist'),
publicPath: '',
},
};
- this example uses handlebar template engine
- update webpack prod config as such:
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'hello-world.html',
chunks: ['hello-world'],
title: 'Hello world',
description: 'Hello World',
template: 'src/page-template.hbs',
minify: false,
}),
new HtmlWebpackPlugin({
filename: 'kiwi.html',
chunks: ['kiwi'],
title: 'Kiwi',
description: 'Kiwi',
template: 'src/page-template.hbs',
minify: false,
}),
],
- sometimes, different pages depend on some common library
- which we do not need to include in each and every generated bundle
- to prevent duplicate code in different bundles
- example lodash lib will be extracted as a separate bundle and imported into the html of bundles that uses it
git checkout single-page-application
npm run dev
Application will be served on the http://localhost:9000/
.
git checkout single-page-application
npm run build
npm start
Application will be served on the http://localhost:3000/
.
git checkout multiple-page-application
npm run dev
Application will be served on the http://localhost:9000/
.
It will show an empty page.
In order to go to the "Hello World" page, go to http://localhost:9000/hello-world.html
.
In order to go to the "Kiwi" page, go to http://localhost:9000/kiwi.html
.
git checkout multiple-page-application
npm run build
npm start
Application will be served on the http://localhost:3000/
.
It will show an empty page.
In order to go to the "Hello World" page, go to http://localhost:3000/hello-world
.
In order to go to the "Kiwi" page, go to http://localhost:3000/kiwi
.