如何优雅的实现express中间件的热跟新

作者: robin
时间:2020.01.06
邮箱:284595745@qq.com
优雅的代码和优雅的我

在日常的开发中,大家是否也有碰到过,需要修改http-proxy-middleware代理设置,但是需要重新启动项目,等待几分钟的情况呢。 那有没有什么办法可以让http-proxy-middleware也可以实现热更新呢。

监听文件变化

既然要实现热更新,首先肯定是监听文件的变化了。我们使用fs.watch来监听文件的修改。

例子:

fs.watch('proxy.js', (event) => {
    if (event === 'change') {
      console.log('proxy.js 文件改变');
    }
  });

express 中间件原理

中间件其实就是一个函数,使用了职责链(责任链)模式实现的,express维护了一个中间件列表,前一个中间件执行完成后,调用next,就会执行下一个中间件。

例子:

function MiddlewareDemo(){
    if(!(this instanceof MiddlewareDemo)){
       return new MiddlewareDemo();
    }
}

MiddlewareDemo.prototype = {
    _middlewareList: [],
    use(middleware){
        // 此处省略了路由地址参数
        if(Array.isArray(middleware)){
            this._middlewareList = this._middlewareList.concat(middleware)
        } else {
            this._middlewareList.push(middleware)
        }
    },
    start(req, res){
        let i = 0;
        const _next = () =>{
            const task = this._middlewareList[i++];
            if(task){
                task(req, res, _next);
            }
        };
        _next();
    }
};


const middlewareInstance = new MiddlewareDemo();

middlewareInstance.use(function(req, res, next){
    console.log(1);
    next();
    console.log(2);
});

middlewareInstance.use(function(req, res, next){
    console.log(3);
    next();
    console.log(4);
});

middlewareInstance.use(function(req, res, next){
    console.log(5);
    next();
    console.log(6);
});
middlewareInstance.start(); // 1 3 5 6 4 2

实现动态修改express中间件

知道了中间件实现原理后,我们只要修改了, express维护中间件的列表就可以了。

例子:

for (let i = 0; i < app._router.stack.length;  i++) {
    if(app._router.stack[i].name === 'router') {
      console.log(app._router.stack[i].name);     
      app._router.stack.splice(i, 1);
      console.log(app._router.stack);          
      break;   
    }
}

如何优雅的实现

虽然上面的方法的可以实现这个需求。请看我们的标题,如何优雅的实现express中间件的热跟新。作为一个优雅的程序猿,怎么允许代码不优雅呢。

例子:

const middlewareList = [];
middlewareList.push(function(req, res, next){
    console.log(1);
    next();
    console.log(2);
});

middlewareList.push(function(req, res, next){
    console.log(3);
    next();
    console.log(4);
});

middlewareList.push(function(req, res, next){
    console.log(5);
    // next();
    console.log(6);
});

function entries(list, fn, next){
    let i = 0;
    const _next = () =>{
        const task = list[i++];
        if(task){
            fn(task, _next);
        } else if (next) {
            next();
        }
    };
    _next();
}

middlewareInstance.use(function(req, res, next){
  entries(middlewareList, (handler, callback) =>{
    handler(req, res, callback);
  }, next)
});
middlewareInstance.use(function(req, res, next){
    console.log('end');
});
middlewareInstance.start(); // 1 3 5 6 4 2

middlewareList[2] = function(req, res, next){
    console.log(5);
    next();
    console.log(6);
};
middlewareInstance.start();// 1 3 5 end 6 4 2

啊,我这该死的优雅(偷笑)

结合http-proxy-middleware在webpack中的使用

例子:

// proxy.js
module.exports = {
  '/proxy': {
    target: 'https://www.baidu.com',
    changeOrigin: true,
    pathRewrite: {
      '^/proxy': ''
    }
  },
};
// webpack.dev.conf.js
const proxyMiddleware = require('http-proxy-middleware');

function proxy(){
  const proxyConfig = fs.readFileSync(path.resolve(__dirname,'./proxy.js'), 'utf-8');
  const proxyTable  = eval(proxyConfig);
  return Object.keys(proxyTable).map(function (context) {
    let options = proxyTable[context];
    if (typeof options === 'string') {
      options = { target: options }
    }
    return proxyMiddleware(options.filter || context, options);
  });
}

module.exports = {
 devServer: {
    after: function (app) {
      let proxyMiddlewareList = proxy();

      function entries(list, fn, next){
          let i = 0;
          const _next = () =>{
              const task = list[i++];
              if(task){
                  fn(task, _next);
              } else if (next) {
                next();
            }
          };
          _next();
      }

      app.use(function(req, res, next){
        entries(proxyMiddlewareList, (handler, callback) =>{
          handler(req, res, callback);
        }, next);
      });
      console.log('开始监听:proxy.js的变化');
      fs.watch(path.resolve(__dirname, './'), (event, filename) => {
        if (event === 'change' && filename === 'proxy.js') {
          console.log('proxy.js 文件改变');
          proxyMiddlewareList = proxy();
          console.log('重新设置 http-proxy-middleware');
        }
      });
    }
  }
}

结束语

既然已经优雅的实现了express中间件的热跟新,那么路由的热跟新还难吗?毕竟原理是一样的

谢谢阅读

相关资料

results matching ""

    No results matching ""