【webpack】webpack构建流程笔记(一)

前言

  • 上一篇是打包规律,这篇是构建流程,了解构建流程便于写插件。

Tapable

  • Tapable是webpack用的类似发布订阅的钩子。
  • 其中sync开头的钩子是同步钩子,async开头的钩子是异步钩子。
  • async钩子里还分成串行Series钩子和并行Parallel钩子。
  • 带有Bail字段的是保险式,只要监听函数有返回值且不为undefined,跳过之后的监听函数。
  • 带有Waterfall字段的是上一步的返回值交给下一步使用。
  • 带有Loop字段是循环类型,如果该监听函数返回true,则这个监听函数会反复执行,如果返回undefined则退出循环。

同步钩子

SyncHook

const { SyncHook } = require('tapable')

let hook = new SyncHook(['name', 'age'])
hook.tap('1', (name, age) => {
    console.log(1, name, age)
})
hook.tap('2', (name, age) => {
    console.log(2, name, age)
})
hook.call('yehuozhili', 111)
  • 就是个发布订阅,在call的时候把tap进其内部的数组取出来执行。
  • 就相当于这个:
class SyncHook {
    constructor(args) {
        this.args = args
        this.arr = []
    }
    tap(name, func) {
        this.arr.push(func)
    }
    call(...args) {
        this.arr.forEach(fn => fn(...args));
    }
}

SyncBailHook

let hook = new SyncBailHook(['name', 'age'])
hook.tap('1', (name, age) => {
    console.log(1, name, age)
})
hook.tap('2', (name, age) => {
    console.log(2, name, age)
    return 2
})
hook.tap('3', (name, age) => {
    console.log(3, name, age)
})
hook.call('yehuozhili', 111)
  • 这玩意是只要有个有返回值就不往下执行了。
  • 实现就是把那个forEach改成for就可以中断了。获取函数的返回值,有值就break就完了。

SyncWaterfallHook

let hook = new SyncWaterfallHook(['name', 'age'])
hook.tap('1', (name, age) => {
    console.log(1, name, age)
    return 1
})
hook.tap('2', (data, age) => {
    console.log(2, data, age)
})
hook.tap('3', (data, age) => {
    console.log(3, data, age)
})
hook.call('yehuozhili', 111)
  • 这玩意特点就是返回值会传给下一个的第一个参数。
  • 实现就是for循环里拿到第一个参数,和返回值对比,返回值有东西就用返回值,否则用参数。

SyncLoopHook

  • 这个钩子有点复杂,先看执行顺序:
let counter1 = 0
let counter2 = 0
let counter3 = 0

let hook = new SyncLoopHook(['name', 'age'])
hook.tap('1', (name, age) => {
    console.log(1, name, age)
    if (++counter1 == 1) {
        counter1 = 0
        return
    }
    return true
})
hook.tap('2', (data, age) => {
    console.log(2, data, age)
    if (++counter2 == 2) {
        counter2 = 0
        return
    }
    return true
})
hook.tap('3', (data, age) => {
    console.log(3, data, age)
    if (++counter3 == 3) {
        counter3 = 0
        return
    }
    return true
})
hook.call('yehuozhili', 111)
  • 先走1,然后因为返回undefined,所以走2,走2返回true,所以得从头走一遍,就又是1和2,这时返回了undefined,就走3,3是true,所以又从头走1走2,这个2还算true,回去继续走1和2,再3,3仍是true,再走次12123,最后返回undefined退出。一共15行输出。
  • 实现:
class SyncLoopHook {
    constructor(args) {
        this.args = args
        this.arr = []
    }
    tap(name, func) {
        this.arr.push(func)
    }
    call(...args) {
        let loop = true
        while (loop) {
            for (let i = 0; i < this.arr.length; i++) {
                let fn = this.arr[i]
                let res = fn(...args)
                loop = typeof res != 'undefined'
                if (loop) break
            }
        }
    }
}

异步钩子

AsyncParallelHook

let hook = new AsyncParallelHook(['name', 'age'])
hook.tap('1', (name, age) => {
    console.log(1, name, age)
})
hook.tap('2', (data, age) => {
    console.log(2, data, age)
})
hook.tap('3', (data, age) => {
    console.log(3, data, age)
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • 异步钩子没有call,只有callAsync,通过回调来拿执行完成结果。
  • 实现就是把最后个参数取出来等循环执行完调用它就行了。
  • 这个还可以注册异步函数:
let hook = new AsyncParallelHook(['name', 'age'])
hook.tapAsync('1', (name, age, callback) => {
    setTimeout(() => {
        console.log(1)
        callback()
    }, 1000);
})
hook.tapAsync('2', (data, age, callback) => {
    setTimeout(() => {
        console.log(2)
        callback()
    }, 1000);
})
hook.tapAsync('3', (data, age, callback) => {
    setTimeout(() => {
        console.log(3)
        callback()
    }, 1000);
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • 这个就有点像Promise。它有个特点,就是同时并行开始执行。
  • 实现:
class AsyncParallelHook {
    constructor(args) {
        this.args = args
        this.arr = []
    }
    tapAsync(name, func) {
        this.arr.push(func)
    }
    callAsync(...args) {
        let argsarr = args
        let fcallback= argsarr.pop()
        let i = 0
        const done=()=>{
            if(++i===this.arr.length){
                fcallback
            }
        }
        this.arr.forEach(fn=>fn(...argsarr,done))
    }
}
  • 还可以使用Promise:
let hook = new AsyncParallelHook(['name', 'age'])
hook.tapPromise('1', (name, age) => {
    return new Promise((res, rej) => {
        setTimeout(() => {
            console.log(1)
            res()
        }, 1000);
    })
})
hook.tapPromise('2', (data, age, callback) => {
    return new Promise((res, rej) => {
        setTimeout(() => {
            console.log(1)
            res()
        }, 1000);
    })
})
hook.tapPromise('3', (data, age, callback) => {
    return new Promise((res, rej) => {
        setTimeout(() => {
            console.log(1)
            res()
        }, 1000);
    })
})
hook.promise('yehuozhili', 111).then((res => {
    console.log('ok')
}), err => {
    console.log('err')
})
  • 这个实现就是promise.all。

AsyncParallelBailHook

let hook = new AsyncParallelBailHook(['name', 'age'])
hook.tapAsync('1', (name, age, callback) => {
    setTimeout(() => {
        console.log(1)
        callback()
    }, 1000);
})
hook.tapAsync('2', (data, age, callback) => {
    setTimeout(() => {
        console.log(2)
        callback(111)
    }, 1000);
})
hook.tapAsync('3', (data, age, callback) => {
    setTimeout(() => {
        console.log(3)
        callback()
    }, 2000);
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • callback有值就提前调最后的执行完成。
  • 这个钩子用Promise的话不看resolve和reject,只要给resolve或者reject里传值,就提前结束。

AsyncSeriesHook

let hook = new AsyncSeriesHook(['name', 'age'])
hook.tapAsync('1', (name, age, callback) => {
    setTimeout(() => {
        console.log(1)
        callback()
    }, 1000);
})
hook.tapAsync('2', (data, age, callback) => {
    setTimeout(() => {
        console.log(2)
        callback()
    }, 1000);
})
hook.tapAsync('3', (data, age, callback) => {
    setTimeout(() => {
        console.log(3)
        callback()
    }, 2000);
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • 这次就不是并行执行了,串行执行。

AsyncSeriesBailHook

let hook = new AsyncSeriesBailHook(['name', 'age'])
hook.tapAsync('1', (name, age, callback) => {
    setTimeout(() => {
        console.log(1)
        callback()
    }, 1000);
})
hook.tapAsync('2', (data, age, callback) => {
    setTimeout(() => {
        console.log(2)
        callback(6)
    }, 1000);
})
hook.tapAsync('3', (data, age, callback) => {
    setTimeout(() => {
        console.log(3)
        callback()
    }, 2000);
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • 同样传值就中断。

AsyncSeriesWaterfallHook

let hook = new AsyncSeriesWaterfallHook(['name', 'age'])
hook.tapAsync('1', (name, age, callback) => {
    setTimeout(() => {
        console.log(1, name, age)
        callback()
    }, 1000);
})
hook.tapAsync('2', (data, age, callback) => {
    setTimeout(() => {
        console.log(2, data, age)
        callback()
    }, 1000);
})
hook.tapAsync('3', (data, age, callback) => {
    setTimeout(() => {
        console.log(3, data, age)
        callback()
    }, 2000);
})
hook.callAsync('yehuozhili', 111, err => {
    console.log('执行完成')
})
  • 跟sync的waterfall差不多。
发布了178 篇原创文章 · 获赞 11 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/yehuozhili/article/details/105301717