27

开源 | Umajs:轻量级 Node.js Web 框架

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI1NDc5MzIxMw%3D%3D&%3Bmid=2247489546&%3Bidx=1&%3Bsn=11f40e7084a74b2db91555a2b24aa777
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

开源二期项目专题系列

(二)

1.开源项目名称:Umajs

2.GitHub地址:

https://github.com/wuba/Umajs

3.简介:Umajs 是58同城推出的一款轻量级 node web 框架。它的中文含义是大熊座,北斗七星都是它的组成部分;正如同 Umajs 也是由不同的 package 所组合在一起。我们希望 Umajs 的每一部分,都是优秀的、闪耀的、经受的住各种大型项目检验的。

Umajs开源项目具备以下特点:

  • 内置丰富的装饰器 (decorator),提供自定义装饰器机制;

  • 依赖注入 (IOC),模块依赖不再需要引入和实例化;

  • 面向切面 (AOP),基于装饰器的 AOP 可以很方便的使用在各种方法上;

  • 统一返回 (Result),让编码更简单清晰;

  • 提供插件机制,灵活扩展框架功能,兼容 Koa2 中间件;

  • 高稳定高性能,源码 TypeScript 开发、单元测试覆盖全。

项目背景

Nodejs 对于前端工程师的重要性不言而喻,它的出现使 JavaScript 成为了最受欢迎的 web 开发语言之一,各类 node web 框架层出不穷,诸如 Express、Koa 等等;但是在应用到实际业务场景时我们还需要额外做一些功能的扩展,为此相应的社区也提供了大量的中间件。

与此同时,随着 JavaScript 承担了更多的大型复杂应用的开发,TypeScript 也渐渐进入了我们的视野:做为 JavaScript 的超集,它的静态类型检查无疑是构建大型 JavaScript 项目的强大助力。

有鉴于此,我们推出了使用 TypeScript 开发的 node web 框架:Umajs 。这里主要和大家分享一下 Umajs 在搭建过程中的设计及其应用的介绍。

架构设计

mieuMnn.jpg!mobile

  • 用户请求达到 router;

  • router 解析请求穿过 plugin 中的中间件,然后到达 controller;

  • controller 可以通过 IOC 调用 service 和 resource;

  • controller、service、resource 等可以通过 AOP 的 Aspect 进行切面开发;

  • controller 返回 Result,Umajs 解析 Result 按 Koa 框架格式返回数据;

  • AOP 可以对 controller、service、resource 进行切面开发,还可以将 middleware 封装成 Aspect.around 对 controller 进行切页面开发;

  • 中间件(middlware)有提供两种形式使用,一种是插件配置(plugin.config.ts),一种是封装成Aspect.around 以装饰器形式使用;

  • Plugin 有两种形式进行扩展,一种中间件形式、一种复合形。

AOP

AOP(Aspect Oriented Programming) 面向切面编程,是一种不修改原代码也能为其动态扩展功能的编程方式。

Umajs 内置了以下五种切面:

  • before:在目标方法之前执行;

  • after:在目标方法之后执行;

  • around:在最开始调用时执行,会将目标方法作为参数传入,可对目标方法进行拦截;

  • afterThrowing:当执行目标方法出现异常时调用;

  • afterReturning:当目标方法有返回值之后执行,在 after 之后执行。

切面可以作用在 class 或者 method 上;一个 class 或者 method 上可以有多个切面,执行顺序如下图所示:

beeU3i.png!mobile

使用 AOP 能够有效的隔离业务中不同部分的逻辑。例如原有目标方法如下:

getList(params){
// do something
return list;
}

假设随着业务的发展,我们需要为这些方法添加埋点统计。此时我们可以通过 AOP 的方式快速扩展目标方法:

@Aspect.before('report')
getList(params){
// do something
return list;
}

相比直接修改 getList 方法,AOP 的方式分离了上报逻辑与数据获取逻辑、降低了耦合度,在保持对业务代码零侵入的情况下完成了功能的扩展。同时该上报方法能够多处复用,提高了代码的可复用性与可维护性。

Result统一返回

统一返回是 Umajs 的另一个特色。我们知道,在大多数 node web 框架中,controller 在处理完业务逻辑后以如下的方式返回处理结果:

// 返回json数据
getList(param){
// do something
ctx.body = { list };
}
// 返回view
index(){
ctx.render('index.tpl');
}

而 Umajs 提供了如下快捷返回方式:

  • Result.send(val, status):快捷返回文本内容;

  • Result.json(data):返回json数据;

  • Result.jsonp(data, callback):以jsonp的形式返回数据;

  • Result.view(templatePath, data):通过渲染模板的方式将数据返回;

  • Result.stream(data, fileName):将文件以流(stream)的方式返回;

  • Result.download(filePath, opts):下载文件。

处理流程如下:

6Zbm2uf.png!mobile

Result 封装了常见的返回值快捷方式,有效的提升了开发效率。同时 Result 可以通过插件进行扩展,为业务提供更多可能性。Result 的意义不仅于快捷方式,在结合了切面、自定义装饰器等功能后,我们可以很轻松的实现对返回值的定制修改。

自定义装饰器

Umajs中大量的功能都通过内置装饰器来提供,诸如:

  • 切面装饰器:@Aspect

  • IOC装饰器:@Resource、@Inject

  • 路由装饰器:@Path、@Private

同时针对高频场景提供了自定义参数装饰器 createArgDecorator,例如通过该方法创建的装饰器能够快速到获取到 query 上的参数:

const Query = createArgDecorator((argKey, ctx) => ctx.query[argKey]);

crateArgDecorator用途不止于此,可以利用它进行参数聚合、参数校验、参数转换等等参数相关的操作。下文我们会详细介绍其强大之处。

在提供丰富的内置装饰器和自定义参数装饰器的同时,框架的使用者也可以自定义符合规范的其它类型装饰器,可以参考 TypeScript 装饰器,此处不再赘述。

应用介绍

上文介绍了Umajs的几个特色,接下来我们一起探索它们在业务场景下的应用。

业务需要根据用户ID查询该用户下的列表数据,API如下:

GET /api/list?userId=userId

对应的controller方法可以如下实现:

getList(){
const { userId } = this.ctx.query;
const list = this.service.getListByUid(userId);
return Result.json(list)
}

虽然上述代码实现了查询功能,但是这种实现是不符合开发规范、存在风险的:

首先我们期望的返回值内存在状态码而不仅仅是数据;其次userId为必填项,此处应该进行参数校验;最后没有进行异常处理。

首先我们创建一个自定义的参数装饰器用于类型检查:

const IdCheck = createArgDecorator((key: string, ctx: IContext) => {
const id = ctx.query[key];

if (id === undefined || id === null || id === '') {
return Result.json({
code: ErrorType.Empty,
msg: `参数 ${key} 不能为空`,
});
}
// 其它校验逻辑
return id;
});


export IdCheck;

然后创建一个切面,该切面内实现一个用于异常处理的around切点:

export default class Demo implements IAspect {
async around(proceedPoint: IProceedJoinPoint) {
try {
const { proceed, args } = proceedPoint;
const result = await proceed(...args);


return result;
} catch (e) {
// 可用 afterThrowing
return Result.json({
code: ErrorType.Error,
msg: e.toString(),
});
}
}
}

改造后的方法如下:

@Aspect('demo')
getList(@IdCheck('userid') uid)){
const list = this.service.getListByUid(uid);
return Result.json(list)
}

通过以上简单的示例我们可以看到:Umajs 的代码在保持业务逻辑清晰的同时,以轻量的扩展实现了参数校验、异常处理、返回值包装等等扩展功能。而这些扩展的装饰器是可以复用在其它方法上的。

对于大型的、复杂度高的工程来说,使用 Umajs 能够在获得良好开发体验的同时,大幅提升工程的可扩展性、可维护性、可复用性,从而提升开发效率。

核心优势

  • 功能强大:内置丰富的装饰器,诸如IOC 装饰器、AOP 装饰器、路由装饰器等等,也可以自定义装饰器;

  • 扩展灵活:通过插件机制扩展框架,提供多种方式兼容 Koa 中间件;

  • 快捷返回:框架内置了常用的返回类型,同时支持扩展;结合切面及装饰器能够覆盖绝大多数业务场景;

  • 开发效率:Umajs内置了大量功能能够提升开发效率;同时 Koa 项目可以平滑的迁移到 Umajs。

未来规划

Umajs会进一步的完善插件机制,使其更易于使用。未来将会增加对于模型驱动开发的支持。我们会持续关注业内的新技术、新趋势、新特性,在合适的情况下会将其引入框架。与此同时,我们会根据社区的反馈不断的完善框架。

如何贡献&问题反馈

我们向广大开发者发出诚挚的邀请,与我们一道共同建设,为 node web 开发效率的提升不断努力。您可以在 https://github.com/wuba/Umajs了解项目源码、使用方式等。同时欢迎提交 PR 或者 Issue,向我们反馈建议和问题。

想了解更多开源项目信息?

与项目成员零距离交流?

扫码加入项目群

一切应有尽有

yYfai2R.jpg!mobile

RRFj636.png!mobile

可添加“58技术小秘书”微信 : jishu-58

添加小秘书微信后由小秘书拉您进项目交流群

作者简介:

王亮,58同城 本地服务技术部 前端工程师

团队简介:

Umajs团队,成员来自58集团各个BG,有着不同的业务背景,因为共同的兴趣而聚集在一起的一群前端工程师。主要维护者有:张志华 、王亮、王莹莹、江峥、薛家志、刘敏、张佳佳、 王斌、邱成林、王晓伟、 武宁、要嵘赫、袁崇恩。

推荐阅读:

开源|Magpie可视化圈选埋点实践

开源 | Picasso:sketch设计稿智能解析工具

开源|Magpie:Magpie在安居客有料业务的落地实践

开源|Magpie:58 跨平台技术应用及 Flutter 实践概览

开源|qa_match更新啦——支持轻量级预训练、提高问答通用性

Nb2iMvQ.jpg!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK