4. 4.Webpack4-webpack钩子

359 阅读4分钟

二十七、1.tapable介绍:Webpack核心Tapable,基于发布订阅原理

  1. 使用 1.start.js
let { SyncHook } = require('tapable');
class Lession{
  constructor(){
    this.hooks = {
      arch: new SyncHook(['name']),
    }
  }
  tap(){ // 注册监听函数
    this.hooks.arch.tap('node',function(name){
      console.log('node',name);
    })
    this.hooks.arch.tap('node',function(name){
      console.log('react',name);
    })
  }
  start(){
    this.hooks.arch.call('kft');
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  1. 2.case.js
class SyncHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  call(...args) {
    this.tasks.forEach((task) => task(...args));
  }
  tap(name, task) {
    this.tasks.push(task);
  }
}

let hook = new SyncHook(['name']);
hook.tap('react', function (name) {
  console.log('react', name)
})
hook.tap('node', function (name) {
  console.log('node', name)
})
hook.call('kft');

二十八、2.tapable:同步钩子hook

  • 同步钩子四方法:SyncHook/SyncBailHook/SyncWaterfallHook/SyncLoopHook
  1. SyncHook:tap注册所有事件,start启动执行所有事件
  2. SyncBailHook 保险hooks,如果return!==undefined,停止向下执行
  • SyncBailHook.start.js
let { SyncBailHook } = require('tapable');
class Lession{
  constructor(){
    this.hooks = {
      arch: new SyncBailHook(['name']),
    }
  }
  tap(){ // 注册监听函数
    this.hooks.arch.tap('node',function(name){
      console.log('node',name);
      return '停止向下执行';
    })
    this.hooks.arch.tap('node',function(name){
      console.log('react',name);
    })
  }
  start(){
    this.hooks.arch.call('kft');
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • SyncBailHook.csse.js 源码
class SyncBailHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tap(name, task) {
    this.tasks.push(task);
  }
  call(...args) {
    let ret; // 当前函数返回值
    let index = 0; // 当前执行的第一个函数
    do {
      ret = this.tasks[index](...args);
    } while (ret === undefined);
  }
}
let hook = new SyncBailHook(['name']);
hook.tap('react', function (name) {
  console.log('react', name);
  return '停止向下执行';
})
hook.tap('node', function (name) {
  console.log('node', name)
})
hook.call('kft');
  1. SyncWaterfallHook: 上下函数联系,流程控制
  • SyncWaterfallHook.start.js
let { SyncWaterfallHook } = require('tapable');
class Lession{
  constructor(){
    this.hooks = {
      arch: new SyncWaterfallHook(['name']),
    }
  }
  tap(){ // 注册监听函数
    this.hooks.arch.tap('node',function(name){
      console.log('node',name);
      return '停止向下执行';
    })
    this.hooks.arch.tap('node',function(name){
      console.log('react',name);
    })
  }
  start(){
    this.hooks.arch.call('kft');
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • SyncWaterfallHook.case.js 源码
class SyncWaterfallHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tap(name, task) {
    this.tasks.push(task);
  }
  call(...args) {
    let [first,...others] = this.tasks;
    let ret = first(...args);
    others.reduce((a,b)=>{
      return b(a);
    },ret)
  }
}
let hook = new SyncWaterfallHook(['name']);
hook.tap('react', function (name) {
  console.log('react', name);
  return 'reactok';
})
hook.tap('node', function (name) {
  console.log('node', name)
  return 'nodeok';
})
hook.tap('webpack', function (name) {
  console.log('webpack', name)
  return 'nodeok';
})
hook.call('kft');
  1. SyncLoopHook 遇到不返回undefined监听函数多次执行
  • SyncLoopHook.start.js
let { SyncLoopHook } = require('tapable');
class Lession {
  constructor() {
    this.index = 0;
    this.hooks = {
      arch: new SyncLoopHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tap('node', (name) => {
      console.log('node', name);
      return ++this.index === 3 ? undefined : '继续执行当前函数';
    })
    this.hooks.arch.tap('node', (name) => {
      console.log('react', name);
    })
  }
  start() {
    this.hooks.arch.call('kft');
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • SyncLoopHook.case.js
class SyncLoopHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tap(name, task) {
    this.tasks.push(task);
  }
  call(...args) {
    this.tasks.forEach(task => {
      let ret;
      do {
        ret = task(...args)
      } while (ret != undefined);
    })
  }
}
let hook = new SyncLoopHook(['name']);
let total = 0;
hook.tap('react', function (name) {
  console.log('react', name);
  return ++total === 3 ? undefined : '继续执行当前函数';
})
hook.tap('node', function (name) {
  console.log('node', name)
})
hook.tap('webpack', function (name) {
  console.log('webpack', name)
})
hook.call('kft');

二十九、3.AsyncParallelHook:异步并行钩子

  1. 异步钩子分为串行、并行,并行钩子需要等待所有并发的异步事件执行后在执行回调方法;
  2. AsyncParallelHook callAsync tapAsync cb() promise tapPromise then
  • start.js 使用
let { AsyncParallelHook } = require('tapable');
class Lession {
  constructor() {
    this.hooks = {
      arch: new AsyncParallelHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log('node', name);
        cb();
      }, 1000)
    })
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log('react', name);
        cb();
      }, 1000)
    })
  }
  start() {
    this.hooks.arch.callAsync('kft', function () {
      console.log('end');
    });
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • case.js 源码
class AsyncParallelHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tapAsync(name, task) {
    this.tasks.push(task);
  }
  callAsync(...args) {
    let finalCallback = args.pop();
    let index = 0;
    let done = () => {
      index++;
      if (index == this.tasks.length) {
        finalCallback();
      }
    }
    this.tasks.forEach((task) => {
      task(...args, done);
    })
  }
}
let hook = new AsyncParallelHook(['name']);
hook.tapAsync('react', function (name, cb) {
  setTimeout(() => {
    console.log('react', name);
    cb();
  })
})
hook.tapAsync('node', function (name, cb) {
  setTimeout(() => {
    console.log('node', name);
    cb();
  })
})
hook.callAsync('kft', function () {
  console.log('end');
});
  1. AsyncParrallelHook promise tapPromise then
  • start.js 使用
let { AsyncParallelHook } = require('tapable');
class Lession {
  constructor() {
    this.hooks = {
      arch: new AsyncParallelHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tapPromise('node', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('node', name);
          resolve();
        }, 1000)
      })
    })
    this.hooks.arch.tapPromise('react', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('react', name);
          resolve();
        }, 1000)
      })
    })
  }
  start() {
    this.hooks.arch.promise('kft').then(function(data){
      console.log('end');
    })
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • case.js 源码
class AsyncParallelHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tapPromise(name, task) {
    this.tasks.push(task);
  }
  promise(...args) {
    let tasks = this.tasks.map(task => task(...args));
    return Promise.all(tasks);
  }
}
let hook = new AsyncParallelHook(['name']);
hook.tapPromise('react', function (name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('react', name);
      resolve();
    }, 1000)
  })
})
hook.tapPromise('node', function (name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('node', name);
      resolve();
    }, 1000)
  })
})
hook.promise('kft').then(function () {
  console.log('end');
})

三十、4. AsyncSeriesHook:异步串行钩子

  1. AsyncSeriesHook tapAsync callAsync 1-2-end
  • start.js 使用
let { AsyncSeriesHook } = require('tapable');
class Lession {
  constructor() {
    this.hooks = {
      arch: new AsyncSeriesHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log('node', name);
        cb();
      }, 1000)
    })
    this.hooks.arch.tapAsync('react', function (name, cb) {
      setTimeout(() => {
        console.log('react', name);
        cb();
      }, 1000)
    })
  }
  start() {
    this.hooks.arch.callAsync('kft', function (data) {
      console.log('end');
    })
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • case.js
class AsyncSeriesHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tapAsync(name, task) {
    this.tasks.push(task);
  }
  callAsync(...args) {
    let index = 0;
    let finalCallback = args.pop();
    let next = () => {
      if (index === this.tasks.length) {
        return finalCallback();
      }
      let task = this.tasks[index++];
      task(...args, next);
    }
    next(...args);

  }
}
let hook = new AsyncSeriesHook(['name']);
hook.tapAsync('react', function (name, cb) {
  setTimeout(() => {
    console.log('react', name);
    cb();
  }, 1000)
})
hook.tapAsync('node', function (name, cb) {
  setTimeout(() => {
    console.log('node', name);
    cb();
  }, 1000)
})
hook.callAsync('kft', function () {
  console.log('end');
})
  1. AsyncSeriesHook promise tapPromise
  • start.js 使用
let { AsyncSeriesHook } = require('tapable');
class Lession {
  constructor() {
    this.hooks = {
      arch: new AsyncSeriesHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tapPromise('node', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('node', name);
          resolve();
        }, 1000)
      })
    })
    this.hooks.arch.tapPromise('react', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('react', name);
          resolve();
        }, 1000)
      })
    })
  }
  start() {
    this.hooks.arch.promise('kft').then(function (data) {
      console.log('end');
    })
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • case.js 源码
class AsyncSeriesHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tapPromise(name, task) {
    this.tasks.push(task);
  }
  promise(...args) {
    let [first, ...others] = this.tasks;
    return others.reduce((p, n) => {
      return p.then(() => n(...args));
    }, first(...args));
  }
}
let hook = new AsyncSeriesHook(['name']);
hook.tapPromise('react', function (name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('react', name);
      resolve();
    }, 1000)
  })
})
hook.tapPromise('node', function (name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('node', name);
      resolve();
    }, 1000)
  })
})
hook.promise('kft').then(function () {
  console.log('end');
})

三十一、5.AsyncSeriesWaterfallHook:异步串行瀑布

  1. AsyncSeriesWaterfallHook tapAsync callAsync cb(null,'result')成功 cb('error','result')跳到最后结果
  • start.js
let { AsyncSeriesWaterfallHook } = require('tapable');
class Lession {
  constructor() {
    this.hooks = {
      arch: new AsyncSeriesWaterfallHook(['name']),
    }
  }
  tap() { // 注册监听函数
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log('node', name);
        cb('error','result');
      }, 1000)
    })
    this.hooks.arch.tapAsync('react', function (name, cb) {
      setTimeout(() => {
        console.log('react', name);
        cb();
      }, 2000)
    })
  }
  start() {
    this.hooks.arch.callAsync('kft', function (data) {
      console.log('end');
    })
  }
}
let l = new Lession();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
  • case.js
class AsyncSeriesWaterfallHook { // 钩子
  constructor(args) {
    this.tasks = [];
  }
  tapAsync(name, task) {
    this.tasks.push(task);
  }
  callAsync(...args) {
    let index = 0;
    let finalCallback = args.pop();
    let next = (err, data) => {
      if (index === this.tasks.length) return finalCallback();
      let task = this.tasks[index];
      if (index === 0) {
        task(...args, next);
      } else {
        task(data, next);
      }
      index++
    }
    next();
  }
}
let hook = new AsyncSeriesWaterfallHook(['name']);
hook.tapAsync('react', function (name, cb) {
  setTimeout(() => {
    console.log('react', name);
    cb(null,'react');
  }, 1000)
})
hook.tapAsync('node', function (name, cb) {
  setTimeout(() => {
    console.log('node', name);
    cb(null,'node');
  }, 1000)
})
hook.callAsync('kft', function () {
  console.log('end');
})