A simple introduction to webpack principle
Preface
We know that webpack
is one of the mainstream module packaging tools in front-end engineering and is used in various front-end engineering projects.
Although most projects will use webpack
to a greater or lesser extent, it may be for most front-end developers. Maybe it's just changing the configuration of webpack
, or even never touching the related files of webpack
, More or less unfamiliar with the configuration and functionality of webpack
.
There are also various scaffolding based on webpack
encapsulation, such as vue-cli
, create-react-app
, umi.js
, etc. A variety of out-of-the-box features are provided, which makes webpack
seem to be getting further and further away from us.
But when one of our projects faces problems that we have to go deep into webpack
to solve, or during an interview, we are asked about webpack
related questions. It's difficult to solve or answer.
So we need to at least have a basic understanding of webpack
, understand its principles, how to write loader
, plugin
, etc.
What is webpack
Quote webpack official website:
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.
Essentially, webpack is a static module bundler for modern JavaScript applications. When webpack handles an application, it recursively builds a dependency graph, This contains each module that the application needs and then package all of these modules into one or more bundles.
In terms of function, the function of webpack is to package and integrate files of different modules together, and ensure that the references between them are correct and executed in an orderly manner. This allows us to split files from the perspective of modules when doing project architecture, and then hand them over to webpack for packaging and integration.
The files in a project include not only html files, CSS files, JavaScript files, picture resources, and Vue-specific .vue
files. Typescript's .ts
file, etc., as well as the code in the project, also needs to be compressed and obfuscated, browser compatibility, etc., Starting a local development server, hot update replacement of modules, etc., can be implemented one by one through various mechanisms provided by webpack
.
For webpack
, it can only recognize JavaScript files itself, and for other resources, it can be implemented through the Loader
feature provided by webpack Identify. Through Loader
, other types of resource files can be converted into valid modules that webpack can handle.
For code obfuscation, local development server, and module hot updates, functional extensions can be achieved through the Plugin
feature provided by webpack.
Module packaging principle
In webpack, there are four basic and core concepts:
- Entries (entry)
- Output
- Loader (Loader)
- Plugin (Plugin)
Entry
Indicates which module webpack should use as the beginning of building its internal dependency graph.
Output
Tell webpack where to output the bundles it creates and how to name these files
Loader
webpack itself can only understand JavaScript files and json files, and loader can convert other types of resource files into valid modules that webpack can handle.
Essentially, webpack loader converts all types of files into modules that can be directly referenced by the application's dependency graph (and the final bundle).
Plugin
Used to perform a wider range of tasks. The scope of plug-ins includes, from packaging optimization and compression, to redefining variables in the environment. The plug-in interface is extremely powerful and can be used to handle a variety of tasks.
modules
In modular programming, developers decompose programs into discrete chunks of functionality and call them modules.
For webpack, any file can be a module.
###Module packaging operation principle
Before talking about the ** module packaging operation principle** of webpack, let’s take a look at how we use webpack. Generally speaking, we localize webpack by writing a configuration file webpack.config.js
. The rough configuration is as follows:
module.exports = {
// Declare the module's entry file
entry: './src/entry.js',
output: {
path: path.resolve(__dirname, 'dist'), // Output directory
filename: 'bundle.js', // File name
},
module: {
rules: [
//Configuration Use babel-loader to convert .js resources
{
test: /\.js$/,
loader: 'babel-loader',
},
// ...more loader
],
},
// Plug-in configuration
plugins: [
new EslintWebpackPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
// ...more plugin
],
// ...more config
}
After webpack
has read the configuration file, the running process is roughly as follows:
- Read the configuration parameters of
webpack
; - Start
webpack
, createcompiler
object, and start parsing the project; - Start parsing from the entry file
entry
, and find the ** dependency module** it imported, recursively traverse the analysis, and form the ** dependency tree**; - Use the corresponding
Loader
to convert the dependency module files for different file types resources, and finally convert them into valid modules of webpack; - During the compilation process,
webpack
throws somehooks
through the publish subscription mode, andwebpack
'sPlugin
is listened to varioushooks
, Execute plug-in tasks, expand the functions ofwebpack
, and interfere with the output results. - According to the output configuration
output
, the packaged built resource file is output.
The compiler
object is a global singleton that controls the entire webpack construction process.
During the build process, a context object compilation
of the current build will also be generated, which contains all the information of the current build. During each hot update or rebuild, compiler
will generate a new compilation
object, responsible for the current build process.
The dependencies between each module depend on the AST
syntax tree. After each module file is parsed through Loader
, The AST syntax tree of module code will be generated through the acorn
library. Through the syntax tree, you can analyze whether this module has dependent modules. Then continue to loop through the compilation and parsing of the next module.
Finally, the bundle file built by webpack is a IIFE execution function.
// Minimize package output file under webpack5
;(() => {
// webpack module file content
var __webpack_modules__ = {
'entry.js': (modules) => {
/* ... */
},
'other.js': (__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
/* ... */
},
}
// Module Cache
var __webpack_module_cache__ = {}
// The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId]
if (cachedModule !== undefined) {
return cachedModule.exports
}
// Create a new module (and put it into the cache)
var module = (__webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {},
})
// Execute the module function
__webpack_modules__[moduleId](module, module.exports, __webpack_require__)
// Return the exports of the module
return module.exports
}
// startup
// Load entry module and return exports
// This entry module can't be inlined because the eval devtool is used.
var __webpack_exports__ = __webpack_require__('entry.js')
})()
In the package demo above, there are only three variables and one function method in the entire immediate execution function. __webpack_modules__
stores the JS content of each compiled file module. __webpack_module_cache__
is used for module cache. __webpack_require__
is a set of dependency introduction functions implemented internally by Webpack. The last sentence is the starting point of the code running, starting from the entry file and starting the entire project.
__webpack_require__
module introduces functions. When we develop modularly, we usually use ES Module
or CommonJS
specification to export/introduce dependent modules. When webpack is packaged and compiled, it will be replaced with its own __webpack_require__
to implement the module introduction and export, thereby implementing the module caching mechanism and smoothing out some differences between different module specifications.