Concepts
- Webpack is a static module bundler for modern JavaScript applications.
- It builds a dependency graph from entry points.
- Combines modules into bundles (static assets).
- Webpack 4+ doesn't require a configuration file but is highly configurable.
Core Concepts:
- Entry
- Output
- Loaders
- Plugins
- Mode
- Browser Compatibility
Entry
- Indicates which module Webpack uses to begin building its dependency graph.
- Determines which other modules and libraries the entry point depends on.
- Default value:
./src/index.js. - Can specify different (or multiple) entry points via the
entry property in webpack.config.js.
Example:
module.exports = {
entry: './path/to/my/entry/file.js',
};
Entry Points Syntax
- Single Entry (Shorthand) Syntax
- Usage:
entry: string | [string] - Good for single entry point applications or libraries.
- Not flexible for scaling configurations.
- Example:
javascript
module.exports = {
entry: './path/to/my/entry/file.js',
};
- Multi-Main Entry (Array Syntax):
- Pass an array of file paths to the
entry property. - Creates a "multi-main entry".
- Useful for injecting multiple dependent files and graphing dependencies into one chunk.
- Example:
javascript
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
- Object Syntax
- Usage:
entry: { <entryChunkName>: string | [string] } | {} - More verbose and scalable way to define entries.
- Allows for separate entry points for different parts of the application (e.g., app and adminApp).
- Example:
javascript
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};
Entry Description Object:
dependOn: Entry points that must be loaded before the current entry point.filename: Specifies the name of each output file on disk.import: Module(s) loaded upon startup.library: Specify library options to bundle a library from the current entry.runtime: Name of the runtime chunk. Creates a new runtime chunk when set.publicPath: Public URL address for the output files of this entry.
Invalid Configurations:
- Using
runtime and dependOn together on a single entry. runtime pointing to an existing entry point name.- Circular dependencies in
dependOn.
Scenarios:
- Separate App and Vendor Entries
- Separate entry points for application code and vendor libraries.
- Allows bundling of vendor code into a separate chunk.
- Enables browser caching of vendor code separately, reducing load time.
- Example:
javascript
module.exports = {
entry: {
main: './src/app.js',
vendor: './src/vendor.js',
},
};
- Multi-Page Application
- Separate entry points for each page of the application.
- Allows for creating separate dependency graphs for each page.
- Enables optimization techniques like
optimization.splitChunks to create bundles of shared application code between pages. - Example:
javascript
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js',
},
};
Output
- Tells Webpack where to emit the bundles it creates and how to name the files.
- Defaults to
./dist/main.js for the main output file and ./dist folder for other generated files. - Configurable via the
output field in webpack.config.js.
Example:
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
- Uses
output.filename and output.path properties. - The
path module (core Node.js module) is used to manipulate file paths.
Usage
- Minimum requirement: set
output.filename within the output object.
module.exports = {
output: {
filename: 'bundle.js',
},
};
- Multiple Entry Points:
- Use substitutions in
output.filename to ensure unique names for each chunk. [name]: name of the chunk.[contenthash]: hash of the chunk's content.
Advanced Configuration:
- Using a CDN (Content Delivery Network) and hashes for assets.
module.exports = {
output: {
path: '/home/proj/cdn/assets/[fullhash]',
publicPath: 'https://cdn.example.com/assets/[fullhash]/',
},
};
- Setting
publicPath dynamically at runtime using __webpack_public_path__.
Loaders
- Processes other types of files and converts them into valid modules.
- Allows importing any type of module (e.g.,
.css files). - Two properties in Webpack config:
test: identifies which file(s) should be transformed.use: indicates which loader should be used.
Example:
module.exports = {
module: {
rules: [
{
test: /\.txt$/, // matches files ending with .txt
use: 'raw-loader', // uses raw-loader to transform
},
],
},
};
module.rules is the correct property to define rules, NOT rules.- Regex for matching files should not be quoted (i.e.,
/\.txt$/ not '\.txt$/').
Using Loaders
- Configuration (recommended): specify loaders in
webpack.config.js. - Inline: specify loaders directly in
import statements.
Configuration
module.rules allows specifying multiple loaders.- Provides a full overview of each loader.
- Loaders are evaluated from right to left (bottom to top).
- Example:
javascript
module.exports = {
module: {
rules: [
{
test: /\.css$/, // Matches .css files
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
},
},
{
loader: 'sass-loader'
}
],
},
],
},
};
Inline
- Specify loaders in
import statements. - Separate loaders from the resource using
!. - Can override loaders from configuration by prefixing the import statement:
!: disables all configured normal loaders.!!: disables all configured loaders (preLoaders, loaders, postLoaders).-!: disables all configured preLoaders and loaders but not postLoaders.- Example:
javascript
import Styles from 'style-loader!css-loader??modules!./styles.css'
Loader Features
- Loaders can be chained, executing in reverse order.
- Loaders can be synchronous or asynchronous.
- Loaders run in Node.js.
- Loaders can be configured with options objects (query parameters are deprecated).
- Loaders can emit additional arbitrary files.
- Loaders follow standard module resolution.
- Loaders are named
xxx-loader (e.g., json-loader).
Plugins
- Used for a wider range of tasks: bundle optimization, asset management, and injection of environment variables.
- To use a plugin,
require() it and add it to the plugins array. - Most plugins are customizable through options.
- Create an instance of a plugin using the
new operator.
Anatomy of a Plugin
- Webpack plugin is a JavaScript object with an
apply method. - The
apply method is called by the Webpack compiler, providing access to the compilation lifecycle.
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('The webpack build process is starting!!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
Using Plugins
Configuration
- Pass a new instance of the plugin to the plugins property in webpack configuration.
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{ test: /\.((js||jsx))$/, use: 'babel-loader' },
],
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};
Node API
- Plugins can be passed via the
plugins property in the configuration.
Mode
- Sets the
mode parameter to development, production, or none. - Enables Webpack's built-in optimizations corresponding to each environment.
- Default value is
production.
Example:
module.exports = {
mode: 'production',
};
Browser Compatibility
- Webpack supports все ES5-compliant browsers (IE8 and below are not supported).
- Requires
Promise for import() and require.ensure(). - Use a polyfill for older browsers.
Configuration
- Webpack's configuration file is a JavaScript file that exports a Webpack configuration.
- You can:
- Import other files via
require(...). - Use utilities on npm via
require(...). - Use JavaScript control flow expressions (e.g.,
?: operator). - Use constants or variables.
- Write and execute functions to generate parts of the configuration.
Avoid:
- Accessing CLI arguments (use
--env instead). - Exporting non-deterministic values.
- Writing long configurations (split into multiple files).
Multiple Targets
- Exporting multiple configurations is possible along with single configuration
Using Other Configuration Languages
- Webpack accepts configuration files written in multiple languages.
Modules
- Break programs into discrete chunks of functionality.
- Provide solid abstractions and encapsulation boundaries.
- Webpack applies the concept of modules to any file in your project.
What is a webpack Module
- Can express dependencies in various ways:
- ES2015
import statement - CommonJS
require() statement - AMD
define and require statement @import statement (CSS/Sass/Less)url(...) or <img src=...> (stylesheets/HTML)
Supported Module Types
- ECMAScript modules
- CommonJS modules
- AMD modules
- Assets
- WebAssembly modules
- Loaders support modules in other languages and preprocessors.
Module Resolution
- A resolver is a library that helps locate a module by its absolute path.
- Webpack uses enhanced-resolve to resolve file paths.
Resolving Rules in Webpack
- Uses enhanced-resolve to resolve path files:
- Absolute paths
- Relative Paths
- Module Paths
Module Federation
- Multiple separate builds should form a single application.
- Separate builds act like containers.
- Can expose and consume code among themselves.
Low-Level Concepts
- Distinguishes between local and remote modules.
- Loading remote modules is asynchronous.
- Containers are created through container entries, which exposes asynchronous access to specific modules.
- Loading and evaluating the module are separated into two steps.
High-Level Concepts
- Each build acts as a container and consumes other builds as containers.
- Shared modules are overridable and provided as overrides to nested containers.
Concept goals
- Expose and consume any module type that webpack supports.
- Chunk loading must load everything needed in parallel.
- Control from consumer to container.
Building Blocks
ContainerPlugin (low level): creates a container entry with exposed modules.ContainerReferencePlugin (low level): adds references to containers and allows importing remote modules.ModuleFederationPlugin (high level): combines ContainerPlugin and ContainerReferencePlugin.
Use cases
- Separate builds per page
- Component library as container
- Dynamic Remote Container
- Promise Based Dynamic Remotes
- Dynamic Public Path
- Troubleshooting- Uncaught Error: Shared module is not available for eager consumption
Dependency Graph
- Any time one file depends on another, Webpack treats it as a dependency.
- Includes non-code assets (images, web fonts).
- Entry points recursively build a dependency graph.
Targets
- Offers multiple deployment targets.
Usage
- Set the
target value to compile to Node.js or similar env.
Multiple Targets
- Create an isomorphic library by bundling two separate configurations.
The Manifest
- Runtime and Manifest are responsible for webpack to connect modularized application when running in the browser
Runtime
- The manifest that webpack needs to connect your modularized application while it's running in the browser
Manifest
- Collection of data used by the runtime will resolve and load modules once they've been bundled and shipped to the browser.
Hot Module Replacement
- Exchanges, adds, or removes modules while an application is running without a full reload.
How It Works
In the Application
- Modules are swapped in and out of an application
In the Compiler
- Compiler emits an update to allow updating from the previous version to the new version.
In a Module
- Opt-in feature that only a ects modules containing HMR code
In the Runtime
- Make an HTTP request to the update manifest
-Runtime supports two methods: check and apply
Why Webpack?
- Bundles JavaScript applications and supports ESM and CommonJS.
- Can be extended to support different assets (images, fonts, stylesheets).
- Automatic Dependency Collection
Under The Hood
- Modules, Entry Points, Chunks, Chunk Groups
Chunks
initial: main chunk for the entry point.non-initial: lazy-loaded chunk.
Output
output.filename: for initial chunk files.output.chunkFilename: for non-initial chunk files.