webpack.js little tail
const webpack = (options, callback) => { //... if (callback) { if (typeof callback !== "function") { throw new Error("Invalid argument: callback"); } if ( options.watch === true || (Array.isArray(options) && options.some(o => o.watch)) ) { const watchOptions = Array.isArray(options) ? options.map(o => o.watchOptions || {}) : options.watchOptions || {}; return compiler.watch(watchOptions, callback); } compiler.run(callback); } return compiler; }
Finally, the compiler is returned
exports.version = version; // ... attribute mount, exposing all the introduced function modules webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter; webpack.WebpackOptionsApply = WebpackOptionsApply; webpack.Compiler = Compiler; webpack.MultiCompiler = MultiCompiler; webpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin; // @ts-ignore Global @this directive is not supported webpack.validate = validateSchema.bind(this, webpackOptionsSchema); webpack.validateSchema = validateSchema; webpack.WebpackOptionsValidationError = WebpackOptionsValidationError;
Some plug-ins are exposed below
const exportPlugins = (obj, mappings) => { for (const name of Object.keys(mappings)) { Object.defineProperty(obj, name, { configurable: false, enumerable: true, get: mappings[name] }); } }; exportPlugins(exports, { AutomaticPrefetchPlugin: () => require("./AutomaticPrefetchPlugin"), BannerPlugin: () => require("./BannerPlugin"), CachePlugin: () => require("./CachePlugin")} )
Another popular explanation:
For example, when you api.AutomaticPrefetchPlugin, you can
Call the method under the automatic prefetchplugin file
The difference between this and the above is that the above is on the webback function object
Compiler.js
To understand Compiler.js
Must understand tapable
Write it again. git address
Let's simply understand it as a plug-in registered through tap
call is the event flow of the run plug-in. There are some asynchronous operations in it
The Compiler is organized as follows
class Compiler extends Tapable { constructor(context) { super(); this.hooks = { //List some of the most frequent shouldEmit: new SyncBailHook(["compilation"]), done: new AsyncSeriesHook(["stats"]), beforeRun: new AsyncSeriesHook(["compiler"]), run: new AsyncSeriesHook(["compiler"]), emit: new AsyncSeriesHook(["compilation"]), afterEmit: new AsyncSeriesHook(["compilation"]), thisCompilation: new SyncHook(["compilation", "params"]), compilation: new SyncHook(["compilation", "params"]), beforeCompile: new AsyncSeriesHook(["params"]), compile: new SyncHook(["params"]), make: new AsyncParallelHook(["compilation"]), afterCompile: new AsyncSeriesHook(["compilation"]), watchRun: new AsyncSeriesHook(["compiler"]), //... } // Add event flow this._pluginCompat.tap("Compiler", options => { switch (options.name) { case "additional-pass": case "before-run": case "run": case "emit": case "after-emit": case "before-compile": case "make": case "after-compile": case "watch-run": options.async = true; break; } }); } watch(){ //... } run(callback) { //... } // Clear input file system purgeInputFileSystem() { if (this.inputFileSystem && this.inputFileSystem.purge) { this.inputFileSystem.purge(); } } emitAssets(compilation, callback) { //... } createChildCompiler( compilation, compilerName, compilerIndex, outputOptions, plugins ) { //... } //... compile(callback){ //... } }
We carefully study the run function, which is carved from the template of tapable usage
compiler.js is the core of webpack
run(callback) { //If running, return error handling if (this.running) return callback(new ConcurrentCompilationError()); //running calls finalCallback const finalCallback = (err, stats) => { this.running = false; if (callback !== undefined) return callback(err, stats); }; //Record the initialization running time const startTime = Date.now(); //Set the running flag to prevent multiple running this.running = true; //Being compiled const onCompiled = (err, compilation) => { //If an error is reported, compilation ends if (err) return finalCallback(err); //If the compilation is not completed if (this.hooks.shouldEmit.call(compilation) === false) { // The Stats module has 1400 lines, // Compiler.js is the core of webpack, and new Stats(compilation) is the core of compiler.js const stats = new Stats(compilation); // stats object mount startTime, endTime stats.startTime = startTime; stats.endTime = Date.now(); // Asynchronous call completes event flow, running ends this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); return; } // Call the emitAsset method. emitAsset is mainly responsible for writing the output file of the file, which does not affect the compilation this.emitAssets(compilation, err => { // Similar to the above, if an error is reported, the compilation ends if (err) return finalCallback(err); // If additional compilation is needed, did not the last compilation complete if (compilation.hooks.needAdditionalPass.call()) { compilation.needAdditionalPass = true; //Again, new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); //Continue asynchronous call time flow this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); // There is an extra time flow this time. Call extra compilation to tell that compilation is finally finished this.hooks.additionalPass.callAsync(err => { if (err) return finalCallback(err); //Call compile and pass the return value of onCompiled into the compile function. The return value of onCompiled is the object of new Stats this.compile(onCompiled); }); }); return; } // If none of the above branches are taken, i.e. the compilation is completed, no additional compilation is required // Call the emitRecords method to record the output this.emitRecords(err => { if (err) return finalCallback(err); // Also new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); // Asynchronous call completion event this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); }); //Finally, no matter which branch is taken, it is the callback function of new Stats(compilation) returning stats. According to the current process, the last branch is called this.emitRecords }); }; // Call beforeRun hook this.hooks.beforeRun.callAsync(this, err => { if (err) return finalCallback(err); // Call run hook this.hooks.run.callAsync(this, err => { if (err) return finalCallback(err); //Read file record this.readRecords(err => { if (err) return finalCallback(err); //Pass the onCompiled function in and call compile this.compile(onCompiled); }); }); }); }
new Stats(compilation) is the core of compiler.js
compilation and Stats correspond to two modules respectively
Line 2500 of compilation.js, line 1400 of stats.js
Let's take a look at the compile function
newCompilationParams() { const params = { // General module factory normalModuleFactory: this.createNormalModuleFactory(), // Context module factory contextModuleFactory: this.createContextModuleFactory(), // Compile dependency compilationDependencies: new Set() }; return params; } compile(callback) { // params values are as follows const params = this.newCompilationParams(); // Asynchronous call beforeCompile hook this.hooks.beforeCompile.callAsync(params, err => { if (err) return callback(err); // Call compile hook this.hooks.compile.call(params); // Finally, there is compilation. I haven't talked about what it is before. Let's see the following functions for new compilation const compilation = this.newCompilation(params); this.hooks.make.callAsync(compilation, err => { if (err) return callback(err); compilation.finish(); compilation.seal(err => { if (err) return callback(err); // Call afterCompile asynchronously and return the callback function this.hooks.afterCompile.callAsync(compilation, err => { if (err) return callback(err); return callback(null, compilation); }); }); }); }); } newCompilation(params) { // compilation is this.createCompilation(), continue const compilation = this.createCompilation(); //Attaching properties to a compilation object compilation.fileTimestamps = this.fileTimestamps; compilation.contextTimestamps = this.contextTimestamps; compilation.name = this.name; compilation.records = this.records; compilation.compilationDependencies = params.compilationDependencies; //Tell the hook to finish calling this.hooks.thisCompilation.call(compilation, params); this.hooks.compilation.call(compilation, params); return compilation; } createCompilation() { // It turns out that Compilation comes from new Compilation, with 2500 lines in total, which is the core of the whole compiler.js return new Compilation(this); }
params is as follows
{ normalModuleFactory: NormalModuleFactory { _pluginCompat: SyncBailHook { // key is the name of the tapable method _args: [Array], taps: [Array], interceptors: [], call: [Function: lazyCompileHook], promise: [Function: lazyCompileHook], callAsync: [Function: lazyCompileHook], _x: undefined }, hooks: { resolver: [SyncWaterfallHook], factory: [SyncWaterfallHook], beforeResolve: [AsyncSeriesWaterfallHook], afterResolve: [AsyncSeriesWaterfallHook], createModule: [SyncBailHook], module: [SyncWaterfallHook], createParser: [HookMap], parser: [HookMap], createGenerator: [HookMap], generator: [HookMap] }, resolverFactory: ResolverFactory { _pluginCompat: [SyncBailHook], hooks: [Object], cache1: [WeakMap], cache2: Map {} }, ruleSet: RuleSet { references: {}, rules: [Array] }, cachePredicate: [Function: bound Boolean], //File path context: '/Users/orion/Desktop/react-beauty-highcharts', parserCache: {}, generatorCache: {} }, contextModuleFactory: ContextModuleFactory { _pluginCompat: SyncBailHook { _args: [Array], taps: [Array], interceptors: [], call: [Function: lazyCompileHook], promise: [Function: lazyCompileHook], callAsync: [Function: lazyCompileHook], _x: undefined }, hooks: { beforeResolve: [AsyncSeriesWaterfallHook], afterResolve: [AsyncSeriesWaterfallHook], contextModuleFiles: [SyncWaterfallHook], alternatives: [AsyncSeriesWaterfallHook] }, resolverFactory: ResolverFactory { _pluginCompat: [SyncBailHook], hooks: [Object], cache1: [WeakMap], cache2: Map {} } }, compilationDependencies: Set {} }
Ultimate conclusion
- Compiler constructor - >
- run method >
- this.compile(onCompiled) ->
- this.compile() execution has compilation - >
- onCompiled execute const stats = new Stats(compilation)
- Finally, return final callback (null, stats);
this.compile(onCompiled) is a high-order function. It can be simply understood that the parameter is a function and returns a function
Sprinkle flowers I want to buy a bottle of skii to reward myself