浅析webpack源码之Compiler.js模块(八)
栏目: JavaScript · 发布时间: 5年前
内容简介:最终返回了compiler下面暴露了一些插件再通俗一点的解释:
webpack.js小尾巴
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; }
最终返回了compiler
exports.version = version; // ...属性挂载,把引入的函数模块全部暴露出来 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;
下面暴露了一些插件
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")} )
再通俗一点的解释:
比如当你api.AutomaticPrefetchPlugin你能
调用AutomaticPrefetchPlugin文件下的方法
这个和上面的不同在于上面的是挂在webpack函数对象上的
Compiler.js正题
要想理解Compiler.js
必须要理解tapable
再写一遍 git地址
我们先简单的理解它为一个通过tap 注册插件
call是run插件的事件流,里面还有一些异步的操作
Compiler整理如下
class Compiler extends Tapable { constructor(context) { super(); this.hooks = { //罗列一些出现频率比较高的 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"]), //... } // 添加事件流 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) { //... } // 清除输入文件系统 purgeInputFileSystem() { if (this.inputFileSystem && this.inputFileSystem.purge) { this.inputFileSystem.purge(); } } emitAssets(compilation, callback) { //... } createChildCompiler( compilation, compilerName, compilerIndex, outputOptions, plugins ) { //... } //... compile(callback){ //... } }
和tapable用法一个模子里刻出来的,我们仔细的研究run函数
compiler.js是webpack 的核心
run(callback) { //如果正在running,返回报错处理 if (this.running) return callback(new ConcurrentCompilationError()); //running调用finalCallback const finalCallback = (err, stats) => { this.running = false; if (callback !== undefined) return callback(err, stats); }; //记录初始化running时间 const startTime = Date.now(); //设置running标志,防止多次running this.running = true; //正在编译 const onCompiled = (err, compilation) => { //如果报错,编译结束 if (err) return finalCallback(err); //如果没有编译完成 if (this.hooks.shouldEmit.call(compilation) === false) { // Stats模块有1400行, // compiler.js是webpack 的核心,new Stats(compilation)是compiler.js的核心 const stats = new Stats(compilation); // stats对象挂载startTime,endTime stats.startTime = startTime; stats.endTime = Date.now(); // 异步调用完成事件流,running结束 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); return; } // 调用emitAsset方法,emitAsset主要负责写入文件输出文件,不影响我们先看编译 this.emitAssets(compilation, err => { // 类似同上, 如果报错,编译结束 if (err) return finalCallback(err); // 如果需要额外的编译,上次的没编译完成吗:cold_sweat: if (compilation.hooks.needAdditionalPass.call()) { compilation.needAdditionalPass = true; //再来一遍new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); //继续异步调用时间流 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); // 这次多了一个时间流,调用额外编译,告知编译终于编完了 this.hooks.additionalPass.callAsync(err => { if (err) return finalCallback(err); //调用compile,把onCompiled的返回值传入compile函数,onCompiled的返回值也就是new Stats的对象 this.compile(onCompiled); }); }); return; } // 如果都不走上面的分支,即编译完成,不需要额外的编译 // 调用emitRecords方法,主要用来记录输出的 this.emitRecords(err => { if (err) return finalCallback(err); // 同样new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); // 异步调用完成事件 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); }); //最终总结,无论走那个分支都是 new Stats(compilation) 返回stats的回调函数,按照目前的流程走的是最后一个分支,调用 this.emitRecords }); }; // 调用beforeRun钩子 this.hooks.beforeRun.callAsync(this, err => { if (err) return finalCallback(err); // 调用run钩子 this.hooks.run.callAsync(this, err => { if (err) return finalCallback(err); //读文件记录 this.readRecords(err => { if (err) return finalCallback(err); //把onCompiled函数传入,调用compile this.compile(onCompiled); }); }); }); }
new Stats(compilation)是compiler.js的核心
compilation和Stats分别对应两个模块
compilation.js 2500行,Stats.js 1400行
接下来我们看一下compile函数
newCompilationParams() { const params = { // 普通模块工厂 normalModuleFactory: this.createNormalModuleFactory(), // 上下文模块工厂 contextModuleFactory: this.createContextModuleFactory(), // 编译依赖 compilationDependencies: new Set() }; return params; } compile(callback) { // params值如下 const params = this.newCompilationParams(); // 异步调用beforeCompile钩子 this.hooks.beforeCompile.callAsync(params, err => { if (err) return callback(err); // 调用compile钩子 this.hooks.compile.call(params); // 终于出现了compilation,之前一直没有讲了compilation是什么,newCompilation我们看如下函数 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); // 异步调用afterCompile,返回回调函数 this.hooks.afterCompile.callAsync(compilation, err => { if (err) return callback(err); return callback(null, compilation); }); }); }); }); } newCompilation(params) { // compilation 是 this.createCompilation(),继续往下 const compilation = this.createCompilation(); //给compilation对象挂载属性 compilation.fileTimestamps = this.fileTimestamps; compilation.contextTimestamps = this.contextTimestamps; compilation.name = this.name; compilation.records = this.records; compilation.compilationDependencies = params.compilationDependencies; //告知钩子调用完毕 this.hooks.thisCompilation.call(compilation, params); this.hooks.compilation.call(compilation, params); return compilation; } createCompilation() { // 原来compilation 是 newCompilation而来,Compilation一共2500行,堪称整个compiler.js的核心 return new Compilation(this); }
params如下
{ normalModuleFactory: NormalModuleFactory { _pluginCompat: SyncBailHook { // key是tapable 方法名 _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], //文件路径 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 {} }
终极总结
- Compiler构造函数 ->
- run方法 ->
- this.compile(onCompiled) ->
- this.compile()执行有了compilation ->
- onCompiled执行 const stats = new Stats(compilation)
- 最后返回 finalCallback(null, stats);
this.compile(onCompiled) 是个高阶函数,可以简单的理解为参数是函数,并且返回一个函数
撒花:rose: :tada::four_leaf_clover:我要买瓶skii犒赏自己
以上所述就是小编给大家介绍的《浅析webpack源码之Compiler.js模块(八)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Introduction to Graph Theory
Douglas B. West / Prentice Hall / 2000-9-1 / USD 140.00
For undergraduate or graduate courses in Graph Theory in departments of mathematics or computer science. This text offers a comprehensive and coherent introduction to the fundamental topics of graph ......一起来看看 《Introduction to Graph Theory》 这本书的介绍吧!