In the compilation event stream, the flow of events is still injected into the detail steps, and the Code flow
// apply = This-compilation // // return compialtionthis. newcompilation (params); this. Applypluginsparallel ("Make", compilation, err = { // callback ... });
After the compilation event stream is triggered, a compilation object is returned directly and then the next event stream make is triggered.
The source of make is in the Entryoptionplugin plug-in, which, whether the entry parameter is a single-entry string, a single-entry array, a multi-entry object, or a dynamic function, injects a make event after the corresponding entry plug-in is introduced.
First, take the simplest single-entry string as an example to start running the make event stream:
// singleentryplugincompiler.plugin ("Make", (compilation, callback) = { // Generates a dependency class of type single entry // dep.loc = name const DEP = Singleentryplugin.createdependency (this. Name); Compilation.addentry (this. Name, callback);});
Compilation.addentry
This returns to the compilation class, calling the prototype function AddEntry.
Class Compilation extends Tapable {// ... //context = default = PROCESS.CWD () //entry = DEP = Singleentrydependency //name = Single entry default to main //callback = the process behindaddentry (context, entry, name, callback) {const slot={name:name, module:NULL }; //initial to [] This. Preparedchunks.push (slot); This. _addmodulechain (Context, entry, (module) and = {/**/}, (err, module) = = {/**/ }); }}
Compilation._addmodulechain
Nothing to say, go directly into the _addmodulechain function:
Class Compilation extends Tapable {// ..._addmodulechain (context, dependency, Onmodule, callback) {//Profile = Options.profile //do not preach then start is undefinedConst START = This. Profile &&Date.now (); //bail = Options.bailConst ERRORANDCALLBACK = This. bail? (err) = ={callback (ERR); }: (Err)={err.dependencies=[dependency]; This. Errors.push (ERR); Callback (); }; if(typeofDependency!== "Object" | | Dependency = = =NULL|| !dependency.constructor) {Throw NewError ("Parameter ' dependency ' must be a dependency"); } //Dependencyfactories contains all of the dependent collectionsConst Modulefactory = This. Dependencyfactories.get (Dependency.constructor); if(!modulefactory) { Throw NewError (' No dependency factory available for Thisdependency type: ${dependency.constructor.name} '); } This. Semaphore.acquire (() = {/**/ }); }}
Profile and bail parameters will probably not be transmitted, all directly ignored.
The next step is to try to get the value of the dependency class from Dependencyfactories, the map object all values are set in the compilation event stream, the details can be seen in section 24 of the flowchart, Portal: http://www.cnblogs.com/ Qh-jimmy/p/8183840.html
Here, the dependency class originates from the singleentrydependency, and the key-value pairs are set at the same location from Singleentryplugin:
// singleentrypluginCompiler.plugin ("Compilation", (compilation, params) = = params.normalmodulefactory; // here Compilation.dependencyFactories.set (singleentrydependency, normalmodulefactory);});
So it's easy to call get here and take out the normalmodulefactory.
And this normalmodulefactory, in section 18, there is a brief introduction and analysis of the ruleset of module.rules processing, Portal: http://www.cnblogs.com/QH-Jimmy/p/8109903.html
Semaphore
After getting the corresponding modulefactory, call the This.semaphore which is to generate a new class:
This New Semaphore (options.parallelism | | 100);
(The name of the class English translation is the signal machine)
The content is relatively simple, over the source code:
class Semaphore {//a number defaults toConstructor (available) { This. Available =available; This. Waiters = []; }; //when available is greater than 0 o'clock execute callback and subtract 1 //otherwise the callback will bounce into the waitersAcquire (callback) {if( This. Available > 0) { This. available--; Callback (); } Else { This. Waiters.push (callback); } }; //attempt to remove the recently bounced callback and execute at the end of the event streamrelease () {if( This. waiters.length > 0) {Const callback= This. Waiters.pop (); Process.nexttick (callback); } Else { This. available++; } }}
The design does look like a signal machine, and the constructor has an initial number of uses and an array of callback to execute.
Each time you call acquire, a callback is passed in, and if the number of times is positive callback is executed and the number of uses minus 1, if the number of times is exhausted, the callback is bounced into the waiters array.
Each time the release is called, the number of uses plus 1 is used to try to fetch the latest callback and execute as soon as possible, if there is no callback to execute.
Normalmodulefactory.create
In other words, the following code can be understood as a simple function call:
this. Semaphore.acquire (() = { modulefactory.create { contextinfo: { "", This . Compiler.name }, Context:context, dependencies: [Dependency] /* */ });});
In this way, the process runs to the Normalmodulefactory prototype method create.
class Normalmodulefactory extends Tapable {/*data = {contextinfo:{issuer: ', compiler:this.compile R.name//undefined}, Context:context,//PROCESS.CWD () dependencies: [Singleentrydepen Dency]}*/Create (data, callback) {const dependencies=data.dependencies; //try to fetch the cacheConst CACHEENTRY = dependencies[0].__normalmodulefactorycache; if(CacheEntry)returnCallbackNULL, CacheEntry); //context = PROCESS.CWD ()Const CONTEXT = Data.context | | This. Context; //Portal File String = =./input.jsConst REQUEST = Dependencies[0].request; Const ContextInfo= Data.contextinfo | | {}; This. Applypluginsasyncwaterfall ("Before-resolve", {contextinfo, context, request, dependencies}, (err, result)
= = {/**/ }); }}
This consolidates the context, the portal file, the Ingress module dependency class, and then starts triggering the flow of events on the Normalmodulefactory class.
About Normalmodulefactory's event flow injection, all in section 24 is described, and then a portal: http://www.cnblogs.com/QH-Jimmy/p/8183840.html
The event flow before-resolve here is not, so follow the tapable in the Applypluginsasyncwaterfall execution mode:
function Applypluginsasyncwaterfall (name, init, callback) { if (! Thisreturn callback (null, init); // More ...}
This will call callback directly, passing NULL with the second argument, as follows:
This. Applypluginsasyncwaterfall ("Before-resolve", {contextinfo, context, request, dependencies},//err = null //result = the object above(err, result) = = { if(ERR)returncallback (ERR); if(!result)returncallback (); //triggering the factory event streamConst FACTORY = This. ApplyPluginsWaterfall0 ("Factory",NULL); //ignored if(!factory)returncallback (); Factory (result, (Err, module)= = {/**/ }); });
This will then trigger the factory event stream, which is directly plugin in the constructor.
class Normalmodulefactory extends Tapable { Constructor (context, resolvers, options) { super (); // ... other property this. Plugin ("Factory", () = = (result, callback) and {thisnull ); if return callback (); /**/ }); }); }}
This also triggers the resolver event stream, which is another plugin event in the constructor.
This section is here first.
. 26-Analysis of Webpack source event flow make (1)