How to build webpack?
1, Operation process
The running process of webpack is a serial process, and its workflow is to connect various plug-ins in series
Events will be broadcast during operation. The plug-in only needs to listen to the events it cares about, and can join this webpack mechanism to change the operation of webpack and make the whole system scalable
The following three steps will be performed from start to finish:
- Initialization process: read and merge parameters from configuration files and Shell statements, and initialize the required plug-ins and configure the parameters required by the execution environment such as plug-ins
- Compilation and construction process: send from the Entry, call the corresponding Loader for each Module to translate the file content, find the Module that the Module depends on, and compile recursively
- Output process: combine the compiled Module into a Chunk, convert the Chunk into a file, and output it to the file system
Initialization process
Read and merge parameters from configuration files and Shell statements to get the final parameters
The configuration file is webpack.com by default config. JS, or specify the configuration file in the form of command, which is mainly used to activate the add ins and plug-ins of webpack
For the content analysis of file configuration, the following notes are given:
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 = { // The entry file is the starting point of module construction, and each entry file corresponds to the last chunk generated. entry: './path/to/my/entry/file.js', // The file path points to (to speed up the packaging process). resolve: { alias: { 'react': pathToReact } }, // The generated file is the end point of module construction, including output file and output path. output: { path: path.resolve(__dirname, 'build'), filename: '[name].js' }, // Here, loaders for processing various modules are configured, including css preprocessing loader, es6 compilation loader and image processing loader. module: { loaders: [ { test: /\.js$/, loader: 'babel', query: { presets: ['es2015', 'react'] } } ], noParse: [pathToReact] }, // Each plug-in object of webpack executes the corresponding method in the event flow of webpack. plugins: [ new webpack.HotModuleReplacementPlugin() ] };
Webpack will webpack config. Copy the configuration items in JS to the options object and load the plugins configured by the user
After completing the above steps, the Compiler compilation object is initialized. The object controls the webpack declaration cycle and does not perform specific tasks, but only performs some scheduling work
class Compiler extends Tapable { constructor(context) { super(); this.hooks = { beforeCompile: new AsyncSeriesHook(["params"]), compile: new SyncHook(["params"]), afterCompile: new AsyncSeriesHook(["compilation"]), make: new AsyncParallelHook(["compilation"]), entryOption: new SyncBailHook(["context", "entry"]) // Many different types of hooks are defined }; // ... } } function webpack(options) { var compiler = new Compiler(); ...// Check options. If the watch field is true, start the watch thread return compiler; } ...
The Compiler object inherits from Tapable and defines many hook functions during initialization
Compile build process
Find all the entry files according to the entry in the configuration
module.exports = { entry: './src/file.js' }
After initialization, the Compiler's run will be called to really start the webpack compilation and construction process. The main process is as follows:
- compile starts compiling
- make analyzes modules and their dependent modules from the entry point and creates these module objects
- Build module
- seal package construction results
- emit outputs each chunk to the result file
Compile compile
After executing the run method, compile will be triggered first, mainly to build a Compilation object
This object is the main executor in the compilation stage. It mainly follows the following processes in turn: the object that performs the main tasks such as module creation, dependency collection, blocking, packaging and so on
make compilation module
After completing the above compilation object, start reading from the Entry file, mainly executing_ addModuleChain() function, as follows:
_addModuleChain(context, dependency, onModule, callback) { ... // Find the corresponding factory function according to the dependency const Dep = /** @type {DepConstructor} */ (dependency.constructor); const moduleFactory = this.dependencyFactories.get(Dep); // Call the create of the factory function NormalModuleFactory to generate an empty NormalModule object moduleFactory.create({ dependencies: [dependency] ... }, (err, module) => { ... const afterBuild = () => { this.processModuleDependencies(module, err => { if (err) return callback(err); callback(null, module); }); }; this.buildModule(module, false, null, null, err => { ... afterBuild(); }) }) }
The process is as follows:
_ addModuleChain receives the entry dependency passed in by the parameter dependency, and uses the corresponding factory function normalmodulefactory The Create method generates an empty module object
The callback will store this module in compilation Modules object and dependencies Module object will also be stored in compilation. Because it is an entry file In entries
Then execute buildModule to enter the process of real building module module content
build module completes module compilation
Here, we mainly call the configured loaders to convert our module into a standard JS module
After converting a module with Loader, acorn is used to analyze the converted content and output the corresponding abstract syntax tree (AST) to facilitate the analysis of the code later in Webpack
Start from the configured entry module, analyze its AST. When you encounter the require and other imported module statements, add them to the list of dependent modules. At the same time, recursively analyze the newly found dependent modules, and finally find out the dependencies of all modules
Output process
seal output resource
The seal method is mainly to generate chunks, perform a series of optimization operations on chunks, and generate the code to be output
The chunk in webpack can be understood as a module configured in the entry or a module introduced dynamically
According to the dependency between the entry and the module, the chunks containing multiple modules are assembled, and then each Chunk is converted into a separate file and added to the output list
emit output completed
After determining the output content, determine the output path and file name according to the configuration
output: { path: path.resolve(__dirname, 'build'), filename: '[name].js' }
Before the Compiler starts generating files, the hook emit will be executed, which is our last chance to modify the final file
Thus, the whole packaging process of webpack is over