0.1.3 • Published 2 years ago

babel-plugin-with-middleware v0.1.3

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

该插件通过在函数上方添加特定注释的方式为函数添加类似于 koa 中间件的功能 (其实就是内置了koa-compose@4.1.0)

配置方法

安装插件

yarn add -D @babel/core@7.14.8 babel-plugin-with-middleware

npm install @babel/core@7.14.8 babel-plugin-with-middleware --save-dev

配置 babel

在 babel 配置文件的 plugins 中添加插件的名称

以.babelrc 为例

{
  "plugins": ["babel-plugin-with-middleware"]
}

一个例子

const timing = async(ctx, next) => {
    let cost = Date.now()
    const rst = await next()
    cost =  Date.now() - cost
    ctx.cost = cost
    return rst
}

const label = functionName => (ctx, next) => {
    ctx.label = functionName
    return next()
}

const print = async (ctx, next) => {
    const rst = await next()
    console.log(`${ctx.label || ""} 耗时:${ctx.cost}ms`)
    console.log(`入参:${JSON.stringify(ctx.params)}`)
    console.log(`返回值:${JSON.stringify(rst)}`)
    return rst
}

// with-middleware label('登录')
// with-middleware print
// with-middleware timing
const login = async (username, password) => {
    const succ = db.user.count({username, password})
    return succ ? '登录成功' : '登录失败'
}

login('tony','ohyeah')

/**
 * 登录 耗时:23ms
 * 入参:["tony","ohyeah"]
 * 返回值:"登录成功"
 * /

上面这个例子中的代码经插件处理后内容如下

function __mdw__compose(middleware) {
  if (!Array.isArray(middleware))
    throw new TypeError("Middleware stack must be an array!")

  for (const fn of middleware) {
    if (typeof fn !== "function")
      throw new TypeError("Middleware must be composed of functions!")
  }

  return function (context, next) {
    let index = -1
    return dispatch(0)

    function dispatch(i) {
      if (i <= index)
        return Promise.reject(new Error("next() called multiple times"))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()

      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

function __mdw__ctxToParams(fn) {
  const _this = this

  return function (ctx) {
    return fn.apply(_this, ctx.params)
  }
}

function __mdw__packing(middlewares) {
  const _this = this

  const composed = __mdw__compose(middlewares)

  return function (...args) {
    return composed.call(_this, {
      params: args,
    })
  }
}

const timing = async (ctx, next) => {
  let cost = Date.now()
  const rst = await next()
  cost = Date.now() - cost
  ctx.cost = cost
  return rst
}

const label = (functionName) => (ctx, next) => {
  ctx.label = functionName
  return next()
}

const print = async (ctx, next) => {
  const rst = await next()
  console.log(`${ctx.label || ""} 耗时:${ctx.cost}ms`)
  console.log(`入参:${JSON.stringify(ctx.params)}`)
  console.log(`返回值:${JSON.stringify(rst)}`)
  return rst
} // with-middleware label('登录')
// with-middleware print
// with-middleware timing

const login = __mdw__packing([
  label("登录"),
  print,
  timing,
  __mdw__ctxToParams(async (username, password) => {
    const succ = db.user.count({
      username,
      password,
    })
    return succ ? "登录成功" : "登录失败"
  }),
])

login("tony", "ohyeah")

下面这些情况可以适用

// with-middleware test
const hello = async () => {}

// with-middleware test
async function hello() {}

// with-middleware test
Greeting.hello = async () => {}

call(
  // with-middleware test
  async function () {}
)

{
  // with-middleware test
  hello: () => {}
}

class Greeting {
  // with-middleware test
  hello() {}

  // with-middleware test
  hello = () => {}
}

// with-middleware test
export const hello = () => {}
// with-middleware test
export const hello = function () {}
// with-middleware test
export default () => {}

依赖

  • @babel/core 7.+

注意

  • 由于经插件处理后的函数总是返回 Promise,所以不应被用于同步函数。
  • 目前仅支持通过单行注释的形式对函数进行包装。
  • 未在 Typescript 环境下测试。
  • 由于是通过注释的形式调用的中间件,所以在打包工具开启了 tree-shaking 时,需要针对性的配置;如 webpack 需要配置 sideEffects(暂未经测试)
  • 不支持生成器函数