前言

Next.js作为一款优秀的React同构框架,开箱即用的特点和社区生态完整一直给我的感觉就是用起来很香,上线了更香,npm上weekly donwload目前已超40万,并有逐渐上涨的趋势,不信看下图
01.png

命令行入口

一般来说想研究一个框架的源码但又不知道从何入手的话,从命令行启动开始入手是一个不错的选择,因为不管上层封装如何复杂,最终的结果都是由命令行去执行,所以可以把命令行当成一个入口自底向上进行抽丝剥茧的反向剖析框架运行过程。

先来看一下next的项目结构
02.png
可以看到packages目录下有5个文件夹:

  • create-next-app:next脚手架
  • next: next.js,也就框架本身
  • next-bundle-analyze: 打包分析插件,类似于webpack-bundile-analyzer
  • next-mdx: mdx.js插件,用jsx写markdown(没用过,有兴趣的可以去看看,不是本文重点)
  • next-server: next.js服务端配置,同构框架的实现核心

所以文章只会重点对nextnext-server进行探索,其他都是配套基建在此就不讲述了。

按照官方文档给出的命令行配置,如下图:
03.png

再点开next文件夹,就可以看到cli中对应的对应的文件:
04.png

没错,就是你了!

启动机制

找到对应的入口后,下面就开始分析next启动机制是怎样的,这里的启动机制主要包括:

  • 处理文件请求(handle request)
  • 匹配约定式路由(match router)
  • 发送node渲染后的html模版(render to html)

以命令行next start为例,因为devprod环境在配置上会有一定的差别,这种差别一般都是在开发环境中要开启比如dev-serverHMR、编译到内存硬盘等配置,并不是同构渲染逻辑的核心,所以从轻就简直接去看next-start.ts是怎么运作的。

next-start.ts

05.png

next-start中的核心是一个叫startServer的方法,然后返回一个promise后执行app.prepare,那就先去看一下startServer是个什么东西。

start-server.ts

06.png

继续抓重点,这里的重点是下面这两个两个:

  • const app = next(serverOptions)
  • const srv = http.createServer(app.getRequestHandler())

看到这里可能会有点懵逼,难道next实例化后调用它的getRequestHandler方法传到http服务同构渲染的过程就完了吗?先不慌,让我来简单解释下同构渲染的流程:

  • 1.前端代码经过生产/开发编译打包后存放到对应路径/内存硬盘中
  • 2.服务端读取打包文件,调用前端提供的渲染方法(比如react提供的renderToString)渲染成字符串,并进行注水等操作,同时把打包后的文件挂载到模版上
  • 3.最后把注水完成的模版字符串通过res.end返回,返回后就是服务端渲染的效果

所以,app.getRequestHandlernext一个专门提供给http.createServer服务的callback,这个cb意义就是通过浏览器请求路由去读取对应的打包文件,然后渲染对应的模版字符串,最后返回res.end(html)完成同构渲染,因此getRequestHandler也可以看作是next启动真正意义上的入口。

再来看看getRequestHandler做了那些哪些事情

next-server.ts

07.png

next-server.tsgetRequestHandler返回私有方法handleRequest,handleRequest接收http服务的requestresponse,以及一个可选参数parseUrl,如果没有传进来那就把req.url传入url(node.js自带的模块)的parse进行解析,可能会有疑问🤔️,解析这个东西有啥用。

简单的说主要解析出protocol(网络协议)、host(主机) port(端口),pathname(路径),query(参数),重要的大概就是这些,其他就不再列举了,前面提到过next会根据路径去匹配路由(也是看了波源码才知道原来约定式路由原来就这么简单吗?!),这个时候就需要用到pathnamequery去匹配。

再往下看解析url后走到了执行run方法,看来run是核心中的核心啊,再去看看这是个什么东西

08.png

Bingo!到这里看到了this.router.match,这不就对应了上面简单总结的同构渲染流程第二步上了吗,先匹配路由再渲染模版。

OK!到这里Next.js的启动机制就已基本解析完成了,完结,撒花🎉🎉🎉。