blog
blog copied to clipboard
nextjs cli部分源码解读
nextjs是一个react服务端渲染框架,主要的优势在于所有的有关babel、wepack一系列配置都是自动生成,无需额外配置,对用户来说降低了入门门槛。这篇文章主要从nextjs的cli入手,剖析一下nextjs中有关于node部分的源码。
cli的主体实现
nextjs主体cli的实现方式是通过cross-spawn
和minimist
实现的。首先看一下nextjs cli 部分的整体结构:
入口文件和相应的bin文件很清晰,结合上面所说的两个package,基本可以猜想到nextjs是通过
cross-spawn
唤起子线程,进而吊起相应的bin文件,然后通过minimist
实现参数的辨识。接下来我们直接单刀直入next文件来证实一下自己的猜想
next文件剖析
翻开next文件,目标直接锁定cli相关的command参数,可以发现如下定义:
const defaultCommand = 'dev'
const commands = new Set([
'init',
'build',
'start',
'export',
defaultCommand
])
通过Set实现对command的统一管理,之后只需要通过Set的has方法便可以匹配到用户process.argv
的输入了。而单独定义出来的defaultCommand
则可以做argv无参数时候的兼容:
if (commands.has(cmd)) {
args = process.argv.slice(3)
} else {
cmd = defaultCommand
args = process.argv.slice(2)
}
通过这里可以看出在无参的时候会默认运行defaultCommand
即dev。
接下来可以扫到这行代码:
const proc = spawn('node', [...nodeArgs, ...[bin], ...args], { stdio: 'inherit', customFds: [0, 1, 2] })
代码虽少,但是内容却不少,这里便是联系next和另外几个bin文件的桥梁,这里也证实了前一章节的猜想,通过子进程直接吊起bin文件。通过这行代码可以发现,在node命令后面有三个参数:
- 第一个参数nodeArgs为node运行时候的参数,在这里只有可能为
--inspect
,即debug相关; - 第二个参数为bin,因为这里用了...展开而bin参数为字符串,所以外面套上了[];
- 第三个参数为args,即command运行时候的参数。
在这里还需要注意一下stdio:'inherit'
,inherit意为”继承“,在node中inherit则继承于process,所以子进程相关的stdin、stdout、stderr分别指向了process.stdin
、process.stdout
、process.stderr
,这样便可以直接通过tty与子进程进行交互。
customFds
作用类似于stdio,其中的0,1,2亦分别代表process的三种情况,但是由于不支持windows平台,所以已经被废弃。在这里写上应该是考虑到了node老版本兼容性的问题。
最终落地文件
bin文件其实并不是最终的逻辑,大部分bin文件中的逻辑指向了./server
文件夹,这里面包含了nextjs作者编写的与webpack插件高度耦合的server。由于和cli的主体逻辑并没有强相关,所以在这里不做进一步解读了。
by 小菜