合并配置项
实例化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')
      常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
 - 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
 
- 提示下载完但解压或打开不了?
 
- 找不到素材资源介绍文章里的示例图片?
 
- 模板不会安装或需要功能定制以及二次开发?
 
                    
    
发表评论
还没有评论,快来抢沙发吧!