从事 Web 开发的程序员,对于先后端分离模式多半不陌生,这也是目前主流的 Web 开发模式,具体关于先后端分离的模式能够参看文章《你不得不了解的先后端分离原理!》,在这里写者不进行说明。html
好了,让咱们进入主题 —— Node.js 先后端分离开发新思路
在进入新思路以前,咱们现须要了解“老思路”是什么?(注意:后面的案例都是以全栈工程师为例,即先后端代码在一块儿)前端
以一种具体情景为例:小牛是一名全栈工程师,喜欢前端后端全干,前端使用目前主流的 Webpack + React 全家桶(或 Vue 全家桶),后端使用 express(或 Koa),小牛在同时开发先后端过程当中,开启两个进程(先后端各一个),同时使用 nodemon 热重启后台服务,使用 Webpack Proxy 转发实现跨域请求,而后哼哧哼哧开发。
如例子:一个先后端分离的简单案例node
Process 1 Process 2 ___________ ____________________ | | Proxy | | | | FrontEnd | <----> | Nodemon | BackEnd | | | | | (cp 1) | ------------- ----------------------
如上示意,该模式启动须要启动两个进程(前端 和 Nodemon),其中 BackEnd 程序做为子进程挂载在 Nodemon 进程,并且前端和 Nodemon 进程经过 Proxy 转发实现通讯。webpack
乍看一下这样挺美好的,可是这种模式的缺陷也很容易暴露出来git
那么对于上述的问题,须要介绍一下咱们今天的主角!程序员
依旧是小牛的例子,大牛一样使用小牛相同的先后端技术栈,但不一样的是,大牛不使用 Nodemon 实现后端程序的热重启,而是使用相似 Webpack HMR(Hot Module Replacement) 的思路,热更新 Node.js 中的 module,具体实现使用 hot-module-require。github
原理图以下,先后端在一个进程(同一个端口)中,经过 Fs Watcher 热替换更新的 Module,而不是全量重启。web
Process _________________________ | | File Watcher | | Frontend | + | | | Backend | ---------------------------
其中核心的 Node.js 端 HMR 实现思路以下算法
首先咱们来看看一个程序的依赖图关系express
index.js
为程序入口,能够经过静态代码分析,获得 index.js
的直接依赖 express/index.js
和 lib/middleware.js
,而后递归地进行,依次获得一个完整的依赖图,算法具体实现参看 detect-dep。某个时候,lib/to-array.js
文件发生改动!
delete require.caches[modulePath]
)其中这一步须要注意环状依赖的处理,须要保证一条依赖路径,不进行重复的依赖更新。
如 lib/to-array.js
,存在两条路径:lib/to-array.js -> lib/middleware.js -> index/js
和 lib/to-array.js -> lib/express-utils.js -> lib/middleware.js -> index/js
以上算法的具体实现参看 hot-module-require,
具体的应用代码能够参看这里
相比与传统模式,新思路的优势十分突出。
用一个具体的场景对比举例,如后端使用内存存储用户 session 数据。如使用传统方式开发,则每一次更新后台代码,都会丢失内存中的用户数据,因此每次都须要从新进行登陆;可是在新方式,只须要不修改用户登陆模块代码,则不会重置用户 session 数据,即不需从新登陆。
Backend 入口 / \ - - 登陆 --> Common <-- 某业务逻辑
如上简易模块依赖图,A -> B 表示 A 依赖 B,因此上图中,Backend 入口直接依赖 “登陆”和“某业务逻辑”,间接依赖“Common”;这时候咱们只有在修改了“登陆”或“Common”的代码,才会触发登陆模块的热更新。
可是新方法也不是完好陷
使用 Node.js HMR 能够实现各类各样的热更新体验,如热更新 proxy,热更新 mock 数据,热更新配置文件...,很是 Cool!