Beginner's Webpack: Step-by-Step Bundling Logic
It is 2024, and almost every developer knows the name Webpack. To keep it short, here is an official description:
Webpack is a powerful static module bundler mainly used for building modern JavaScript applications. It treats various resources in the application (like JavaScript, CSS, images, etc.) as modules and can bundle these modules into one or more files for efficient loading in the browser.
The strength of Webpack lies in its flexibility and extensibility. It supports code splitting, hot module replacement (HMR), and a rich plugin system, allowing developers to manage complex project builds more effectively.
Let's discuss practical aspects. You may want to know how Webpack handles your code, especially your CSS, JS, and static resources.
We will use a React Single Page Application (SPA) as an example to show you Webpack's real responsibilities.
Assume our React app's entry file is index.tsx
. Webpack will start parsing the application's dependencies from this file.
Initially, Webpack focused on processing JS. It bundles your JS code and its dependencies into one or more JS files. Later, Webpack added support for CSS and static files (like JPG images) through loaders.
In the first step, Webpack encounters your index.tsx
file, which usually imports your App component. Here is an example:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
At this point, Webpack detects that this is a .tsx
file and uses ts-loader
or babel-loader
to process TypeScript code. If using babel-loader
, it works with @babel/preset-typescript
to convert it to JS and @babel/preset-react
to convert JSX syntax to plain JS.
In simple terms:
- File Detection:Webpack identifies the
.tsx
file. - Loader Choice:
- With
ts-loader
, it directly processes TypeScript to output JavaScript. - With
babel-loader
, you need to configure:@babel/preset-typescript
:Converts TypeScript to JavaScript.@babel/preset-react
:Converts JSX to plain JavaScript.
- With
Now, our written code has been converted from TSX to ES5 JS.
If you're curious about how Babel converts TSX files to ES5, please check here.
For library code, they may follow different packaging standards like AMD, CMD, UMD, CJS, and ESM. Since these different formats cannot run together, Webpack standardizes them for us.
Note that the process of standardization can be complex, so we won't detail it here. If you want to learn how to convert, please refer to this article
Now that our JS files are bundled, how do we handle CSS and SVG resources?
style-loader
andcss-loader
:If the app uses CSS, Webpack will parse@import
andurl()
statements usingcss-loader
and dynamically insert the CSS into the DOM withstyle-loader
.
Webpack treats CSS files as modules. It parses them with css-loader
, and then style-loader
injects the CSS into a <style>
tag in the HTML document's <head>
.
This method is convenient during development, as style changes reflect immediately in the browser without a refresh.
However, in production, inlining CSS may bloat the file size and affect performance. Usually, other plugins like MiniCssExtractPlugin
are used to extract CSS into separate files in production builds.
Thus, the Webpack documentation states:
Do not use
style-loader
withmini-css-extract-plugin
.
-
sass-loader
:If the app usesSass
orSCSS
,sass-loader
will compile these files into CSS. -
file-loader
或url-loader
:These loaders handle static resources (like images and fonts).file-loader
copies files to the build directory, whileurl-loader
converts small files into Data URLs.
Here is a possible Webpack configuration snippet showing how to configure these loaders:
module.exports = {
entry: './src/main.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpg|gif|svg)$/,
use: 'file-loader'
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
}
};
The extensions
array specifies which file extensions can be omitted when resolving modules. When you import a module without an extension
, Webpack tries to find the file in the order listed in extensions. For example:
- If you write
import MyComponent from './MyComponent'
, Webpack will look for:./MyComponent.tsx
./MyComponent.ts
./MyComponent.js
This simplifies import statements and makes the code cleaner.
In addition to loaders, Webpack offers a rich set of plugins to extend its functionality. Plugins can perform more complex tasks during the build process, like optimization, compression, and output management.
Webpack plugins provide an interface to access the build process. Developers can register plugins on specific hooks to execute tasks at different stages of the build. Plugins typically use Webpack's API to modify the build process or generate output.
HtmlWebpackPlugin simplifies the generation of HTML files. It automatically creates an HTML file that includes the bundled JavaScript and CSS files.
This is especially important for SPA projects, as it reduces manual configuration.
When you need to extract CSS into separate files, MiniCssExtractPlugin is commonly used. It extracts CSS from JavaScript and creates a standalone CSS file to optimize loading performance.
This CleanWebpackPlugin plugin automatically cleans the output directory before each build, ensuring only the latest build files exist and preventing old files from causing issues.
DefinePlugin allows you to create global constants at compile time, often used for setting environment variables (like different configurations for development and production).
Congratulations! You have finished reading this document, and you have mastered most of the knowledge about Webpack.