egg.js和nestjs使用场景对比

提醒你们:注意文章的时效性,毕竟不一样的时间节点,框架成熟度不一样。分享这篇文章主要是但愿可以让你们认清框架的定位和应对的业务场景,框架没有好坏之分,只有是否适合本身。html

原标题:关于nodejs-web框架的调研java

做者:xingyuzhenode

日期: Feb 25, 2018git

原文: github.com/xingyuzhe/b…github

如下内容实际上是补漏, 算是对1月份一点工做的总结。web

加入了新团队, 初次接触, 粗略的查看了一些项目(nodejs server端), 发现存在几个问题:redis

对于新成立的团队,存在以上问题能够理解, 本次是讨论和解决第一个问题。typescript

对于集团范围内而言,同种技术存在多种不一样规范和框架很正常, 可是对于一个几十人的团队而言, 资源有限,仍是集中力量统一一下效率高些, 有鉴于此, 以为作一个种子项目比较合适: 一个企业定制框架, 共同维护, 同步更新, 信息共享和沉淀最佳实践。express

跟领导聊了一下, 总结了一下当前状态团队对于这块内容的一些主观诉求:npm

  1. 框架实现够简单, 团队能全面掌控, 低风险。
  2. 给新手从基础开始学习的机会, 就是但愿除了知足业务需求以外, 团队也能获得成长。
  3. 一个企业基础框架应知足的基本要求: 约束规范、扩展机制、安全、高效业务开发
  4. 最终仍是但愿能沉淀出一套本身的轮子

根据上面的要求, 筛选出了eggjsnestjs2个web框架, 其中nestjs是团队一部分同窗比较喜欢和尝试使用了的。

首先从外层信息作些调查。

我通读了eggjs和nestjs的文档,查阅了一些资料, 简单对好比下:

-- eggjs nestjs
github stars 7014 4291
github forks 720 250
gitHub dependents 1591/305 0/0
npm search results 565 53+
github contributors 101 31
github core contributors 4(10+) 1(2+)
github releases 49 19
github issues 86/1416 20/347
基础框架依赖 koa2 express
文档 业界良心 通常
核心原理 载入-挂载 模块容器-依赖注入(经过装饰器和元数据实现)
核心理念 微内核-插件机制 组件树-装饰器-流程控制

eggjs的特色和解决的主要问题:

  1. 经过载入代码-自动挂载代码到对象的方式解决了处处写import/require的问题, 再也不须要手动维护模块之间的依赖关系, 核心就是一个loader, 虽然官方没有说起, 可是本人开下脑洞猜想, 这个模块的实现灵感有可能来自于坟头草已经一人高了的seajs, -_-, 这种挂载模式实现起来简单粗暴直接高效, 可是一个小问题就是在使用TS编写代码的时候, 会影响书写体验的流畅度, 毕竟不很OOP。
  2. 微核心 + 插件机制(这个理念其实一直以来都是代码组织的核心手段, 本人在之前开发播放器和IM客户端这块时感同身受), 大部分功能经过插件实现, 从而剥离非核心生命周期功能代码, 达到解耦/下降思惟负担的目的; 另一点就是跨模块API调用比较自由没有限制, 这个地方带来便捷的同时也有可能须要必定约束。
  3. 统一约束和规范, 对开发人员强约束, 保证不会出现千人千面的代码风格和设计。
  4. 种子项目 + 渐进式开发, 能够沉淀出本身的插件和业务框架、最佳实践
  5. 针对业务中遇到的常见问题基本都给出了解决方案, 插件丰富, 配套齐全
  6. 内部实现了进程间管理和通讯功能
  7. 文档但是说是比较细致了, 基本把web这块涉及到的点都涵盖了, 仅仅通读文档对新手而言都会有很多收获
  8. 核心开发者较多, 属于团队项目, 总体看来比较严谨
  9. 沉淀时间较长, 正式发版2年, 实际发展了4年
  10. 明肯定义了agent和app模式, 也实现了schedule功能

nestjs的特色和解决的主要问题:

  1. 经过模块容器-依赖注入维护组件树的模式解决了处处写import/require的问题, 再也不须要手动维护模块之间的依赖关系, 另外编码方式与java十分类似。
  2. 组件树容器模式也达到了解耦效果, 实现方式上很大程度上受angular-module影响, 可是须要指定节点component的依赖关系, 跨模块调用严格依赖于声明. 其实这块功能github有独立的项目专作这个东西, 例如: InversifyJS | bottlejs, nestjs 本身实现了这个模块。
  3. 统一约束和规范, 对开发人员强约束
  4. 大量使用装饰器, 这个未支持的特性须要编译, 对代码阅读上可能会提升一些难度
  5. 流程控制上比较细致, 提出了filter、pipe、guard、interceptor这些明确的概念, 虽然这些工做在正常开发时也会作, 可是明确提出来并制定规范仍是颇有必要的
  6. 明确了Exception Layer的概念
  7. 默认使用/推荐TS开发
  8. 自带微服务实现
  9. 自带swagger接口文档生成功能
  10. 核心开发基本就做者一人, 属于我的项目, 提交记录比较难看, 前期的提交很是随便, 到后期才慢慢改善
  11. 2017年1月立项, 2017年5月发布第一个正式版本, 尚需时日印证

从上述状况来看, 2个框架都在123这几项作了工做, 完成了一个框架所应具有的基本诉求; 整体上看eggjs更加成熟和全面, 配套/生态相对完善的多, 低风险; nestjs则比较青涩和单一, 可是在组件树、流程控制、错误层级处理上有本身的特点, 理念上更加OOP,学习并吸取这些理念是很可取的, 但暂时不建议在核心产品线上投入使用。

eggjs

详细阅读了核心相关代码, 粗略阅读了cluster等一些模块和插件的代码, 代码读起来整体比较流畅, 发现框架的核心实现很是简单明了:

  • 框架基础依赖一个很是独立的loader模块, 功能就是加载代码文件和挂载函数到指定对象。

  • 框架自己核心类只有6个: koa自己的application, context, response, request, egg自身新增的controller, service 这2个类, 后续全部的挂载动做都在这几个类上面进行

  • 框架明确了app, framework, plugin3个概念, 依赖方式大概是这样:

  • 框架启动的核心流程主要是这样:

    因为eggjs本身实现了cluster, 自带进程管理和进程间通讯功能, 因此egg自身部署时并不须要pm2这个工具, 官方文档上也对此作了解释。不过因为这块内容的引入(cluster还涉及到schedule、socket等功能),给框架自己带来了大量额外的代码和逻辑, 整体提高了框架的复杂度。

    可是有些时候因为某些缘由并不但愿直接使用框架提供的cluster解决方案, 另外我查看了下pm2的API, 也是有进程间通讯的API的, 固然用起来可能没有自定义实现时那样自由, 也还没有据说该API有被普遍使用过, 不过, cluster相关的内容可否做为一个扩展包, 而不是强耦合进框架核心流程中? 这样框架自己更加简单纯洁, 或者更容易被接受一些?

    为此尝试抽离了eggjs的核心代码, 目标是仅保留最最核心的代码(移除cluster等周边代码), 具有egg的扩展机制和能正常直接使用eggjs的周边插件, 结果最后只须要几百行代码, 不多几个文件便可完成。后续在此基础上整理了一个上层框架, 预想做为业务项目的基础框架使用,主要涉及如下一些方面:

    1. 抽离eggjs的核心代码, 仅保留其插件机制和对应的约束规范
    2. 集成经常使用扩展函数、中间件、插件
    3. 集成多节点/进程下消息推送解决方案示例
    4. 集成schedule定时任务模块

    以后花了点时间用这个上层框架开发了一个抽奖小项目, 开发体验还算流畅, 虽然说是草量级项目, 不过也是五脏俱全, 做为example还挺适合。

    nestjs

    粗略查看了下nestjs的源码, nestjs的核心其实就是一个IoC模块管理容器的实现, 这块内容的逻辑实现做者处理的仍是相对复杂的多, 这里吐槽下做者的代码组织方式和略显随意的注释大量的接口引用和糟糕的历史提交记录...,真是额外提升了阅读的难度. TypeScript的加持和做者本人的光环也不能阻挡这一点。言归正传, 这里说下它的核心原理和流程。

    要想理解nestjs的源码先要理解和掌握如下知识:

    1. ES6的proxy,reflect
    2. TypeScript的decorator
    3. inversion of control (IoC)的基本概念
    4. 必定TypeScript基础.
    5. 如何经过decorator和元数据实现依赖注入
    • container类: 用于存储全部模块
    • scanner类: 递归提取出全部模块并存储到容器中; 提取出模块间的关联关系和模块自身的各类类以及内部联系,并存储到模块中;
    • module类: 存储自身的关联模块、组件、可注入类、控制器类
    • injector类: 依赖注入的核心环节, 在全部模块的内容和关系都被扫描出后, 来建立实例,
    • instanceLoader类: 使用Injector来加载模块的各类实例, 这个过程很复杂, 伴随递归和各类判断

    这个IoC容器实现的核心流程是这样: scanner扫描全部module并提取关系存入module->module存入 container-> injector建立实例(依赖注入)-> instanceLoader加载实例

    咱们再拿nestjs实现上面eggjs版本lottery的例子, 大概是这样:

    结合源码和实际开发体验来讲:

    • eggjs框架自己的模块管理(扩展机制)很是简单, 复杂度主要在于cluster这块内容和为此配套的周边设施(命令行工具、调试工具),可是这个复杂度是脱离于核心以外的东西。
    • nestjs的复杂度主要在于IoC模块管理器这块的实现上, 实际上这个东西理论上能够独立出来, 以此下降框架自己逻辑的复杂度。

    从整体上讲, eggjs相对成熟, 更贴合实际开发需求。 nestjs的优点就是在一些细节上的约束和控制以及理念上的新颖(仅相对node-web框架而言), 可是这些并非核心诉求。

    另外eggjs团队作的工做内容相对于nestjs而言至关的多, 这些与人力、时间资源的投入是分不开的。

最后, 对于想要的新框架的处理结论已经有了:

1 社区模式(节省资源)

  • 直接在eggjs基础上作一个上层框架, 吸取nestjs的一些优势, 做为插件/扩展内容去完善框架自己.

2 造轮子模式

  • eggjs插件机制 + nestjs流程控制 + component模式(可选) => 新轮子

3 所应具有的特性

  • 约束规范
  • 沉淀/扩展模式
  • 模块依赖管理
  • 集成typescript开发环境
  • 集成API文档输出方案
  • 环境配置
  • 多节点/cluster解决方案
    • socket.io
    • schedule
  • 集成经常使用插件功能
    • logger
    • cookie
    • session
    • security
    • i18n
    • redis
    • sequelize
    • multipart
    • oauth
    • onerror
    • passport
    • view
    • role
    • crypto
  • 定义控制流/数据流约束规范
    • schema
    • pipe
    • interceptor
    • guard
  • migration
  • 微服务
  • 错误分级
  • 监控
  • 测试用例/代码覆盖率
  • 调试
  • 压力测试

补充: 随着各类工具的发展, 加上eggjs使用也有一段时日,最初一些模糊的预感变得清晰: 1 egg内置cluster模式带来的额外麻烦太多, 如今各类配套工具逐渐完善, 这个功能并无什么用

2 egg模块隔离度不够但矛盾的是有时候又有限制, 简单的说就是代码组织模式上做为框架不够好, 须要自行定制上层规范; egg的是plugin模式, 相对于nest的component模式仍是不够用;

3 egg的ts开发的流畅度差那么一点

4 实际的项目, 须要各类配套设施、工具、系统的协做联合,框架只是一个组成部分, 就应该只作它应该作的事就能够了

各有优劣, 诉求不同, 选择就不同: 1 eggjs: 短平快稳,上手极快, 文档完善,配套齐全, 能极大缩短工期。 2 nestjs: 有点追求, 复杂度高的协做项目, 核心诉求是代码组织模式的

以前egg很好的知足了咱们的诉求, 可是下一个项目, 会考虑使用nestjs或者自行开发框架(足够闲的话)。

egg官方维护者atian25的评论:点击详见

atian25补充下几点:

  • Cluster 里面并无 schedule

  • Socket 那个是为了实现高级的 IPC

  • Cluster 仍是很建议使用的,若是有什么特殊的定制需求,何不如提下 RFC/ISSUE 你们讨论下

  • egg-core + egg-cluster 才成为 egg,你要是想定制,能够相似 egg-core + my-cluster(虽然不建议)

  • 框架复杂度其实反而是下降了,由于 PM2 的代码比 egg-cluster 复杂多了

  • Egg 的定位是框架的框架,跟 thinkjs/sails/nest 这些是无法直接对比的,由于不是一个层面的概念。就像你只能对比 Express 和 Koa,而不能对比 nest 和 Koa,由于 nest 是在 Express 之上的封装。

    基于 Egg 封装的针对某个领域的上层框架,才能对比。譬如彻底能够用官方的 TS 方案,再封装集成几个装饰器,成为一个上层框架。就能够拿来对比了。

相关资料

Egg & Node.js 从小工坊走向企业级开发

选择JavaScript开源库时,你须要考虑这些问题

12个因素

关注公众号,发现更多精彩

相关文章
相关标签/搜索