blog icon indicating copy to clipboard operation
blog copied to clipboard

nextjs cli部分源码解读

Open xtx1130 opened this issue 7 years ago • 0 comments

nextjs是一个react服务端渲染框架,主要的优势在于所有的有关babel、wepack一系列配置都是自动生成,无需额外配置,对用户来说降低了入门门槛。这篇文章主要从nextjs的cli入手,剖析一下nextjs中有关于node部分的源码。

cli的主体实现

nextjs主体cli的实现方式是通过cross-spawnminimist实现的。首先看一下nextjs cli 部分的整体结构: issue18-1 入口文件和相应的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.stdinprocess.stdoutprocess.stderr,这样便可以直接通过tty与子进程进行交互
customFds作用类似于stdio,其中的0,1,2亦分别代表process的三种情况,但是由于不支持windows平台,所以已经被废弃。在这里写上应该是考虑到了node老版本兼容性的问题。

最终落地文件

bin文件其实并不是最终的逻辑,大部分bin文件中的逻辑指向了./server文件夹,这里面包含了nextjs作者编写的与webpack插件高度耦合的server。由于和cli的主体逻辑并没有强相关,所以在这里不做进一步解读了。 by 小菜

xtx1130 avatar Feb 17 '18 02:02 xtx1130