A Practical Walkthrough of Webpack’s Core Concepts

My Notes on Webpack: How It Actually Works and How to Use It
What is Webpack
Webpackis a static module bundler for modernJavaScriptapplications, designed to efficiently manage and maintain every resource in a project.
Modern front-end development has become very complex, and we need (which is what webpack can do):
- Develop in a modular way (not only js, but also html and css)
- Use some advanced features to speed up development efficiency or improve security, such as developing script logic through ES6+ and TypeScript, and writing css style code through sass, less, etc.
- Perform compression, merging, and other related optimizations on code
When processing a program, Webpack internally builds a dependency graph, mapping every module required by the project, and then generates one or more bundles accordingly.
Webpack can
- Compile code (e.g. es6 => es5)
- Module integration (bundle multiple es6 files into a single bundle.js)
- Module division (supports different types of front-end modules, unified modular solutions, all resource files can be controlled via code loading) (e.g. .png/.hbs => .png, .css/.scss => .css)
Webpack Build Process
webpack’s running process is a serial process, and its workflow is to connect various plugins together. During its operation, it broadcasts events, and plugins only need to listen to the events they care about to join thiswebpackmechanism and change its behavior, giving the entire system good extensibility.
Initialization Process
- Read and merge parameters from the configuration file (
webpack.config.js) andShellcommands to derive the final parameters.
var path = require('path');
var node_modules = path.resolve(__dirname, 'node_modules');
var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
module.exports = {
// Entry file, the starting point of module construction, each entry corresponds to a generated chunk.
entry: './path/to/my/entry/file.js',
// File path alias (can speed up bundling).
resolve: {
alias: {
'react': pathToReact
}
},
// Output file, the endpoint of module construction, including output file and output path.
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
},
// Configure loaders for each module, including css preprocessors, es6 compilers, image loaders, etc.
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
],
noParse: [pathToReact]
},
// Webpack plugin objects, executed in corresponding methods within webpack’s event flow.
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
- Initialize options: webpack copies each configuration item in
webpack.config.jsinto theoptionsobject and loads user-configuredplugins. - Initialize Compiler object, which controls the lifecycle of
webpack. It does not perform specific tasks but coordinates operations.
Compilation Process
- Find all entry files based on the
entryconfiguration
module.exports = {
entry: './src/file.js'
}
- Call the
runmethod ofCompilerto start the webpack build process:compile: Start compilationmake: Analyze entry points and their dependent modules, create module objectsbuild-module: Build modules, mainly calling configured loaders, to transform modules into standardJSmodules
Output Process
seal: Seal build results- The
sealmethod generateschunks, optimizes them, and produces the output code - Assemble multiple modules into
Chunksaccording to entry and dependency relationships, then convert eachChunkinto a separate file and add it to the output list emit: Output each chunk to the result files
- The
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
}
Loader and Plugin
Loader
- By default, when encountering
importorrequire,webpackonly supports packagingjsandjsonfiles. For types likecss,sass,png, etc., corresponding loaders are needed to parse the content. - When
webpackencounters an unrecognized module, it will look for a parsing rule in the configuration.
- Ways to configure loaders:
- Configuration file (recommended): specify in
webpack.config.js- Inline: explicitly specify loader in each
importstatement- CLI: specify in
shellcommand
- For example, using three loaders to process
.cssfiles:
module.exports = {
module: {
rules: [
{
test: /\.css$/, // regex for matching
use: [ // loaders to call
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
},
{ loader: 'sass-loader' }
]
}
]
}
};
- Common loaders:
- css-loader: analyzes relationships between
cssmodules and merges into onecss - style-loader: mounts
css-loaderoutput into the page’sheadvia<style>tag - file-loader: moves resource modules to the output directory and returns the file path as a string
- css-loader: analyzes relationships between
rules: [
...,
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name]_[hash].[ext]", // placeholders
outputPath: "./images", // output directory
publicPath: './images', // public URL
}
}
}
]
Plugin
Pluginis a computer application that interacts with the main program to provide specific functionality.
- Plugins run at different stages of webpack (hooks / lifecycle), giving webpack flexible features such as bundling optimization, resource management, environment variable injection, etc., aiming to solve problems loaders cannot.
- A plugin is essentially a JavaScript object with an
applymethod. The parameter ofapplyiscompiler, so the plugin can access all lifecycle hooks during compilation.
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('Webpack build process started!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
Difference Between Loader and Plugin
- Concept
- Loader is a file loader that loads and processes resource files (e.g. compile, compress), then bundles them.
- Plugin gives webpack flexible capabilities like optimization, resource management, and environment variable injection.
- Runtime
- Loaders run before bundling files.
- Plugins can run throughout the entire compilation lifecycle.
- Writing loaders
thispoints to webpack, so cannot use arrow functions- Receives one parameter: the file content passed by webpack
thisis provided by webpack, giving access to loader information
- Writing plugins
- Implement an object with an
applymethod that receivescompiler
- Implement an object with an
Webpack Hot Module Replacement
HMRstands forHot Module Replacement, meaning hot swapping of modules. It allows replacing, adding, or removing modules during runtime without refreshing the entire application.
- Enable HMR:
const webpack = require('webpack')
module.exports = {
// ...
devServer: {
// Enable HMR
hot: true
}
}
- At this point, if we modify and save a
cssfile, it updates in the page without refreshing. However, if we modify and save ajsfile, the page still refreshes. Therefore, unlike other webpack features,HMRis not available out-of-the-box. We need to specify which modules should perform HMR:
if(module.hot){
module.hot.accept('./util.js',()=>{
console.log("util.js has been updated")
})
}