preface

Webpack has grown to include: Module packaging, code segmentation, load on demand, HMR, tree-shaking, file listening, Sourcemap, Module Federation, devServer, DLL, multi-process, etc. In fact, the entire vast system of Webpack can be abstracted into three aspects of knowledge:

1. Core construction process

2. Load the resource loader

3. Package optimization Plugin

The core build process converts resources into resource files that can be recognized by the browser, the Loader loads resources and converts resource formats into file formats that can be recognized by the main process, and the Plugin optimizes the packaging process throughout the build process.

Noun explanation

If you are new to this article and don’t know what some of the nouns mean, you can read the following noun explanation module carefully. Those familiar with Webpack can skip this module:

Entry: Compilation Entry, starting point for Webpack compilation, manually configured by users

Compiler: Compiler manager. After Webpack starts, Compiler objects are created that survive until the end of the packaging process

Compilation: The manager of a single edit process, such as Watch =true, runs with only one compiler, but each time a file change triggers a recompilation, a new Compilation object is created

Dependence: Dependency objects on which Webpack records dependencies between modules

Module: All resources in Webpack will be in the form of Module objects, all operations on resources, translation, merge are based on the Module as the basic unit (various resource files =>ast=> Module)

Chunk: When compiled and ready for output, Webpack organizes modules into chunks according to specific rules. These chunks correspond to the final output to some extent

Loader: A resource content converter that converts content FROM A to B

Plugin: In the process of webpack construction, corresponding events will be broadcast at specific times, plug-ins listen for these events and intervene in the compilation process at specific time points. The compilation process of Webpack is carried out around these key objects. For more detailed and complete information, please refer to the WebPack knowledge graph.

Functions and differences between Loader and Plugin

Loader and Plugin are singled out here because they are the two most important modules in Webpack, and they are often conceptually confused by newbies.

1, loader– static resource loader, load all kinds of resource files, its function is single, responsible for loading all kinds of resource files;

Plugin — The plugin system is responsible for optimizing the packaging process, such as deleting common code in chunk files, compressing images, etc. Any function you want to implement can be implemented through plugin system.

The functions of loader and plugin modules can be understood. What you need to know is that you can use all written Loaders to help you load and convert all kinds of resource files through configuration files, and you can use ready-made plugin plug-ins to optimize your packaging process. All these need to accumulate experience. In addition, you can optimize your packaging process by customizing plug-ins!

Tips: Webpack can greatly improve the performance of front-end projects.

With webPack’s right-hand man in mind, let’s focus on the core packaging process:

The build process

The packaging and construction process of Webpack completes two functions of content transformation and resource merger. The implementation includes three stages: initial build configuration, building module dependency and generating chunk files. First, let’s have a general understanding:

Initialize the build configuration

Initialization parameters: read the user’s configuration parameters from the configuration file webpack.config.js, configuration objects, Shell parameters (command line), and obtain the final configuration parameters combined with the default webpack configuration

Create Compiler objects: Create Compiler objects using configuration parameters

Initialize the build environment: this includes injecting built-in plug-ins, registering various module factories, initializing RuleSet collections, loading configured plug-ins, and so on

Start compiling: Execute the run method of the Compiler object

Determine the entry: according to the entry entry file, call compilition.addEntry to convert the entry file to dependence object, and find out the dependency between modules.

2. Construction Stage:

Make: The module object was created according to the dependence of entry. Loader was called to translate the module into standard JS content, JS interpreter was called to convert the content into AST object, and the module that the module depended on was found out. Then this step was recursed until all the files that the entry depended on were processed by this step

Complete module compilation: after the last step of recursive processing of all accessible modules, we get the translated content of each module and the dependency diagram between them

3. Generation Stage:

Output resource (SEAL) : Assembles chunks containing multiple modules based on the dependencies between entries and modules, converts each Chunk into a separate file and adds it to the output list. This step is the last chance to modify the output content

Write to a file system (emitAssets) : After determining the output content, determine the output path and file name based on the configuration, and write the output content to the file system

Next, let’s take a look at what was accomplished in the three phases:

1. Configuration Stage:

Look at the picture and speak:

First, Webpack merges process.args + webpack.config.js into the user configuration

Call validateSchema to verify the configuration

Call getNormalizedWebpackOptions + applyWebpackOptionsBaseDefaults merge the final configuration

Creating compiler objects

Iterate through the user-defined set of plugins and execute the apply method of the plug-in

Call the new WebpackOptionsApply().process method to load various built-in plug-ins

The construction phase

Have you ever thought about the question:

How do you handle resource dependencies during Webpack compilation? What state transitions have resource files undergone?

These questions can be answered in the construction phase. In the construction stage, the resources and resource dependencies were analyzed recursively from entry, and module sets and dependencies between modules were gradually built within compilation objects. The core process was shown in the diagram:

First, you call the handleModuleCreate method to build module subclasses based on the file type

The runLoaders translation Module content that calls the Loader-Runner repository is typically translated from various resource types to JavaScript text

Call Acorn to parse the JS text into an AST

Traverse the AST, trigger various hooks in HarmonyExportDependencyParserPlugi plug-in to monitor exportImportSpecifier hooks, interpretation of JS text corresponding resource dependency

Call the Module object’s addDependency to add the dependency to the Module dependency list

After the AST traverses, it calls module.handleParseResult to handle module dependencies

For new dependencies on The Module, call handleModuleCreate to control the flow back to the first step

After all dependencies have been resolved, the build phase ends.

Module => AST => Dependences => Module (standard JS module). This requires that the final result of loaders must be a standard JavaScript syntax that can be processed by Acorn. For example, for images, the image binary needs to be converted to something like export default “data:image/ PNG; Base64, XXX “or export default “http://xxx” url format.

Compilation works recursively through this process, gradually resolving the contents of each module and module dependencies so that output can be packaged around those contents.

Summary Review the issues mentioned at the beginning of the chapter:

How do you handle resource dependencies during Webpack compilation? What state transitions have resource files undergone?

1. In the process of traversing the AST collection, Webpack identifies import statements such as require/ import and determines the dependency of modules on other resources.

Dependences => Module (standard JS module).

Generate the phase

The WebPack build phase revolves around Modules and the build phase revolves around chunks. After the construction phase, WebPack has enough module content and module relationship information to start generating the final resource. At the code level, we start executing the compilation.seal function:

Seal seal seal seal seal seal One of my favorite summing-up quotes from a big bull describes the whole SEAL process as “putting modules into a honeypot”. The seal function mainly completes the transformation from module to chunks. The core flow is shown in the diagram:

A brief overview:

First, build the ChunkGraph object for this compilation

Modules collection is traversed, and the rules dynamically introduced by modules according to entry/ are assigned to different chunks. After traversing the compilation.modules collection, complete chunks are obtained. CreateXxxAssets (createXxxAssets) is used to traverse the Module /chunk, and the compilation.emitAssets (createXxxAssets) method is used to record the assets information to the compilation.assets object

The SEAL callback is fired, and control flows back to the Compiler object. The key logic of this step is that modules are organized into chunks according to rules. The chunk encapsulation rules built into Webpack are relatively simple:

1. The entry and the module that the entry touches are combined into a chunk

2, use dynamic import statements to import modules, each into a chunk (tips: bold)

Chunk is the basic unit of the output. By default, these chunks correspond to the final output resources one by one. According to the above rules, it can be roughly deduced that an entry will correspond to a resource, and modules introduced through dynamic import statements will also correspond to a resource.

conclusion

The overall build process of WebPack still relies heavily on the Compilation and Module objects, but the idea is much more than that. To the user, WebPack is essentially a collection of plug-ins that can be controlled by Tapable to run on the WebPack event stream. In business development, whether to improve the efficiency of packaging construction, or to reduce the size of packaging files, we can write webpack plug-in to control the flow.

The best way to learn Webpack is practice. After understanding the principle of Webpack, you need to configure it by yourself. You can see which loader loads which module and which plugin optimises which packaging process. And line and cherish!

Hope you can become a Webpack god soon!

reference

1, zhuanlan.zhihu.com/p/363928061

2, juejin. Cn/post / 684490…