阅读 197

webpack运行过程(1)(webpack流程)

合并配置项

实例化Compiler

加载所有插件

runWebpack()  // webpack-cli/lib/webpack-cli.js createCompiler()  // webpack-cli/lib/webpack-cli.js webpack()   // webpack/lib/webpack.js create()   //webpack/lib/webpack.js var compiler = createCompiler(webpackOptions) // webpack/lib/webpack.js const createCompiler = rawOptions => {     // 合并配置项,即将在webpack.config.js中配置的和webpack自带的配置合并     const options = getNormalizeWebpackOptions(rawOptions)     // 实例化compiler     const  compiler = new Compiler(options.context, options)     // 遍历插件,执行插件的apply()方法     if(Array.isArray(options.plugins)){         for(const plugin of options.plugins) {             if(typeof plugin === "function"){                 plugin.call(compiler, compiler)             }else{                 plugin.apply(compiler)             }         }     }     // 实例化WebpackOptionsApply,并执行它的process()方法     new WebpackOptionsApply().process(options, compiler)     return compiler } 复制代码

加载 入口插件EntryPlugin

// 调用WebpackOptionsApply //此处的options是我们在webpack.config.js中配置的内容 new WebpackOptionsApply().process(options, compiler) // webpack/lib/webpack.js // 调用EntryOptionPlugin插件 process(){  // webpack/lib/WebpackOptionsApply.js ...     new EntryOptionPlugin().apply(compiler)     compiler.hooks.entryOption.call(options.context, options.entry) ... } // EntryOptionsPlugin插件的apply方法 apply(compiler){     compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => {         EntryOptionPlugin.applyEntryOption(compiler, context, entry)         return true     }) } // applyEntryOption是EntryOptionPlugin类的静态方法 static applyEntryOption(compiler, context, entry){     if(typeof entry === "function"){          }else{         const EntryPlugin = require("./EntryPlugin");         // 遍历入口对象的key         for(const name of Object.keys(entry)){             const desc = entry[name]             ...             for(const entry of desc.import){                 new EntryPlugin(context, entry, options).apply(compiler)             }         }     } } // webpack/lib/EntryPlugin.js // 在EntryPlugin插件的apply()方法中我们调用了compiler的make钩子 // make钩子: compilation结束之前执行 apply(compiler){     ...     const { entry, options, context } = this     ...     compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => {             })      } 复制代码

实例化Compilation, 根据入口的数量,1次或多次调用该实例对象的addEntry()方法, addEntry()主要是将entry放入到AsyncQueue中

 compiler.run()    //webpack/lib/Compiler.js compiler.compile() //webpack/lib/Compiler.js compiler.newCompilationParams()   //webpack/lib/Compiler.js compiler.createNormalModuleFactory()   //webpack/lib/Compiler.js const normalModuleFactory = new NormalModuleFactory() // constructor()   //构造函数,webpack/lib/NormalModuleFactory.js  const compilation = compiler.newCompilation()  //webpack/lib/Compiler.js // 调用compiler.hooks.make.callAsync即是执行compiler.hooks.make.tapAsync // compiler.hooks.make.callAsync只会执行一次 // compiler.hooks.make.tapAsync 内部执行次数 等于 入口的个数 compiler.hooks.make.callAsync(compilation, err=>{}) //webpack/lib/Compiler.js compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback)=>{ })   // webpack/lib/EntryPlugin.js // 以下是EntryPlugin插件apply()方法中 apply(compiler){     ...     const { entry, options, context } = this     ...     compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => {         // 有n个入口,这里就会被执行n次         compilation.addEntry(context, dep, options, err => {             callback(err)         })     })      } 复制代码

简化版

class Compilation {     constructor(){     }     addEntry(entry){         console.log(entry)     } }  const compilation = new Compilation() compilation.addEntry('app.js') compilation.addEntry('search.js') 复制代码

实例化一个异步队列(AsyncQueue),存储一个entry; 多个entry对应多个异步队列

 //webpack/lib/Compiler.js compilation.addEntry()  compilation._addEntryItem() //webpack/lib/Compilation.js compilation.addModuleTree() // webpack/lib/Compilation.js compilation.handleModuleCreation()  // webpack/lib/Compilation.js compilation.factorizeModule() //webpack/lib/Compilation.js  compilation.prototype.factorizeQueue = new AsyncQueue({}) //webpack/lib/Compilation.js  Compilation.factorizeQueue.add()  //webpack/lib/Compilation.js  AsyncQueue.add() //webpack/lib/util/AsyncQueue.js 复制代码

宏任务执行AsyncQueue的_ensureProcessing()方法,该方法内会遍历前面加入到AsyncAueue中的所有entry,做后续操作,未完待续,期待下期的 webpack运行过程(2)

// 在执行宏任务之前会将多个entry加入到AsyncQueue的_children中 // 宏任务执行root._ensureProcessing setImmediate(root._ensureProcessing) _ensureProcessing()  //webpack/lib/util/AsyncQueue.js // 这里的_children可以理解为多个入口 // 遍历多个入口 for(const child of this._children){     // _parallelism为并发数     while(this._activeTasks < this._parallelism){         const entry = child._queued.dequeue();         if(entry === undefined) break;         this._activeTasks++         entry.state = PROCESSING_STATE         child._startProcessing(entry)     } } _startProcessing()  //webpack/lib/util/AsyncQueue.js 复制代码

上述简化版实现

class Compilation {     constructor(){     }     addEntry(entry){         const asyncAueue = new AsyncQueue()         asyncAueue.add(entry)     } }  class AsyncQueue{     constructor(){         this.list = []     }     add(entry){         this.list.push(entry)         // 这里要使用bind指定this,不然this会执行执行调用者setImmediate         setImmediate(this._ensureProcessing.bind(this))     }     _ensureProcessing(){         for (let index = 0; index <  this.list.length; index++) {             const entry = this.list[index];             this._startProcessing(entry)                      }     }     _startProcessing(entry){         console.log(entry)     } } const compilation = new Compilation() compilation.addEntry('app.js') compilation.addEntry('search.js')


作者:yanessa_yu
链接:https://juejin.cn/post/7031457009979359263


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐