Express、Koa(+常用中间件) 已经满足了 Web 框架的两个核心要素
- 提供 web 开发常见的各种基础功能
- 提供一套规范的编码方式,让开发者可以聚焦在业务逻辑实现,代码就可以在框架内按照预期执行
Express 到今天(2020.06)都是 Node.js 社区最流行的 Web 框架,但主要应用在 Web 辅助界面或者参与成员比较少的小型项目中,在中大型 Node.js 应用中一般都会基于 Express 或者 Koa 封装一个上层 Web 框架让团队使用,开发业务逻辑
Express、Koa 简单、拓展型强,使用非常灵活,深受独立开发者喜爱,但缺少规则约束,即使是标准的 经典的 MVC 模型也会有各种各样的写法,大型项目往往涉及多人协作,需要大家在一定的规约下书写代码,降低协作成本
因此开发中大型 Node.js 项目需要定制 Web 框架,框架内置实现团队约定,提供业务场景常用的功能,提升大型项目开发、维护效率
如何选择框架
Nide.js 社区 Web 框架百花齐放,除了 Express 一枝独秀,其余框架差距并不算大,谈不上谁最流行
2020.06.26 数据
框架 | npm 周下载 | git start |
---|---|---|
Express | 10,658,949 | 49.1k |
Koa | 511,945 | 29.5k |
Egg.js | 7,968 | 15.7k |
nest.js | 233,766 | 28.1k |
fastify | 88,904 | 14.7k |
hapi | 209,230 | 12.5k |
restify | 85,288 | 9.8k |
sails | 28,029 | 21.4k |
和没有最好只有最合适的编程语言类似,Node.js Web 框架起步时间差不多,社区流行的框架经过自然淘汰并没有明显不合适的,但根据各自的特性有自己擅长的领域
- 如果是开发小型项目,Express、Koa 无疑是第一选择,Express 最为简单,场景的功能都有提供,Koa 需要自己配置一些中间件,洋葱模型的中间件在复杂中间件处理上有一定优势
- restify 专注于开发 REST api
- fastify 强调自己的性能优势(大型项目的性能往往不是框架慢导致的)和 JSON Schema based 路由特性
- next.js 比较贴合前端习惯,可以使用 React 构建一个完整的 Web 应用程序
大部分框架都有自己的特性,随着 TypeScript 的流程,各个框架也都有了支持,从数据上可以看到 nest.js 有一定的领先,主要有几个特性
- 面向 AOP 编程,类似 Node.js 版的 spring(前端看起来可能更 Angular)
- 默认使用 TypeScript/Rx.js,代码分析、智能补全
- 支持 TypeORM
- 自带微服务实现
是不是看到这几个特性就已经心动了,nest.js 最大的特点还是 AOP 的编程,为代码带来了非常强的约束和确定性,但也让开发者被迫写大量模板化的代码,喜欢和讨厌这点的人一样多,阿里开源框架 Midway 使用了同样的特性
egg.js 是什么
首先 egg.js 是『约定优先于配置』的一个 Node.js web 框架
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。 https://eggjs.org/zh-cn/intro/index.html
egg.js 对应用目录做了约定,按照约定创建的目录会被自动加载,具体含义可以参考:egg.js 目录结构
egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── response_time.js
│ ├── schedule (可选)
│ | └── my_task.js
│ ├── public (可选)
│ | └── reset.css
│ ├── view (可选)
│ | └── home.tpl
│ └── extend (可选)
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可选)
| ├── config.local.js (可选)
| └── config.unittest.js (可选)
└── test
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
一个典型的 MVC 模型,同时支持了中间件、应用配置、单元测试,这么看起来就是个普通的 Node.js Web 框架,只不过是目录做了约定而已
但站位公司的 Web 架构师角色,仅仅有目录约定并不能完全解决多团队、多业务开发协同问题,在一般的 Web 框架中还存在大量的配置文件和开发指导文档用来说明
- 用什么模板引擎,虽然没有太大区别,但开发者会各选各的
- 数据库用什么服务来处理
- kv 存储的基础配置
- 多语言处理工具
- 登录处理工具
- docker file 配置
- …
如果仅仅开发一个项目不用担心这些,技术负责人做好应用初始化然后提交代码,其他开发者下载代码后开发业务逻辑即可,但如果公司有 2000 多名前端、数百个 Node.js 应用,有差异化的配置诉求,架构师该如何解决?
这也是阿里 Node.js 发展过程中遇到的实际问题,内部不同团队根据自己需求开发了不同的 Web 框架,和 Node.js 社区一样,框架做的工作看起来没多大区别,但各有各的特性,中间一些相似功能因为各自的开发体系导致不能通用,普遍存在复制相似代码,包一个外壳的行为
Web 框架做的事情太少就会导致可用性差,做的太多就会比较定制,而 Egg 是框架的框架,帮助团队的技术负责人,来定制适合特定的业务场景的上层业务框架。egg.js 的名称含义正是这样,像 egg 一样孕育 Web 框架
其它框架通过初始化代码和配置文档也可以做到这一点,但 egg.js通过独特的 plugin、Framework 机制可以在共同约定基础上定制出团队业务场景的 Web 框架,所有约定、工具、插件集成在一个独立的 npm 包中(也就是 egg 孕育出的框架),业务开发者下载即可使用,在保持团队开发约定的基础上极大提升了 Web 框架的定制性
图片来源:egg.js 核心开发 天猪:https://zhuanlan.zhihu.com/p/154643011
Chair、Midway Nut 等都是基于 egg.js 开发的 Web 框架
egg.js 官网对架构师定义团队框架的描述更清晰、准确
如果你的团队遇到过:
- 维护很多个项目,每个项目都需要复制拷贝诸如
gulpfile.js
/webpack.config.js
之类的文件。- 每个项目都需要使用一些相同的类库,相同的配置。
- 在新项目中对上面的配置做了一个优化后,如何同步到其他项目?
如果你的团队需要:
- 统一的技术选型,比如数据库、模板、前端框架及各种中间件设施都需要选型,而框架封装后保证应用使用一套架构。
- 统一的默认配置,开源社区的配置可能不适用于公司,而又不希望应用去配置。
- 统一的部署方案,通过框架和平台的双向控制,应用只需要关注自己的代码,具体查看应用部署
- 统一的代码风格,框架不仅仅解决代码重用问题,还可以对应用做一定约束,作为企业框架是很必要的。Egg 在 Koa 基础上做了很多约定,框架可以使用 Loader 自己定义代码规则。
为此,Egg 为团队架构师和技术负责人提供
框架定制
的能力,框架是一层抽象,可以基于 Egg 去封装上层框架,并且 Egg 支持多层继承。这样,整个团队就可以遵循统一的方案,并且在项目中可以根据业务场景自行使用插件做差异化,当后者验证为最佳实践后,就能下沉到框架中,其他项目仅需简单的升级下框架的版本即可享受到。
在阿里内部有一个最流行的基于 egg.js 的 Web 框架 begg,begg 相对于 egg 做了几个封装
- 使用 egg 保证了开发规范的一致性
- begg 命名的来源 b 是 BUC 的缩写,一个专门负责 BU 账号登录的功能
- 集成了内部发布、部署工具
- 集成了阿里内部常见基础服务:rpc、mysql、redis 等
begg 是独立的 npm package,开发者下载后就直接有了上述功能,极大的适应了内网应用,70% 的内部应用都使用 begg(毕竟也有其它定制框架满足差异化需求),架构师再也不用听开发者吐槽不愿接手其他人维护的应用了
后面的章节中从环境配置、路由、MVC、中间件、插件来介绍一下 egg.js 的使用,了解了其使用机制后再自定义插件、Framework,体验 egg.js 渐进式开发的魅力
参考
- egg.js 核心开发者 天猪 —— 如何为团队定制自己的 Node.js 框架?(基于 Egg)