最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • webpack运行过程(1) - 掘金

    正文概述 掘金(yanessa_yu)   2021-11-17   672

    合并配置项

    实例化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')
    

    起源地 » webpack运行过程(1) - 掘金

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元