1 先搞清楚:Node.js 命令行的本质是什么
很多人把 Node.js 命令行理解成“在终端里敲 node 文件名”,这只说对了一半。Node.js 的 CLI 实际上是运行时环境的配置入口——你敲下的每一个 flag,都在改变 V8 引擎、事件循环、模块加载器、调试协议的行为方式。
语法结构只有一行:
node [options] [script.js] [arguments]
四个位置各有分工:
-
node:可执行程序本身,负责启动 JavaScript 运行时。 -
options:命令行标志,例如--watch、--inspect、--version,决定运行时怎么跑。 -
script.js:要执行的入口文件。 -
arguments:传给脚本的附加参数,脚本内通过process.argv读取。
一个典型调用:
node --watch app.js
这里 --watch 是选项,app.js 是入口脚本。Node.js 会监听文件变化并自动重启进程,省去手动 Ctrl+C 再重跑的循环。
我刚接触 Node.js 时习惯用
nodemon做热重载,后来 Node.js 原生支持了--watch,很多中小项目直接用它就够了,少装一个依赖,少一份配置维护成本。但如果项目需要监听多个目录、忽略特定文件、配合自定义重启钩子,nodemon仍然更灵活。选型要看项目复杂度,不是原生的一定更好。
2 Node.js 命令行选项速查表
下面这张表按官方文档顺序整理,共 31 项,后面会挑重点展开讲。
| 序号 | 选项 | 作用 |
|---|---|---|
| 1 | -v, --version |
打印 Node.js 版本号 |
| 2 | -h, --help |
打印命令行选项帮助 |
| 3 | -e, --eval "script" |
把参数当作 JavaScript 直接求值 |
| 4 | -p, --print "script" |
与 -e 相同,但会打印结果 |
| 5 | -c, --check |
只检查脚本语法,不执行 |
| 6 | -i, --interactive |
即使 stdin 不是终端也打开 REPL |
| 7 | -r, --require module |
启动时预加载指定模块 |
| 8 | --no-deprecation |
静默弃用警告 |
| 9 | --trace-deprecation |
打印弃用项的堆栈跟踪 |
| 10 | --throw-deprecation |
把弃用警告升级为错误抛出 |
| 11 | --no-warnings |
静默所有进程警告 |
| 12 | --trace-warnings |
打印进程警告的堆栈跟踪 |
| 13 | --trace-sync-io |
事件循环首轮后检测到同步 I/O 时打印堆栈 |
| 14 | --zero-fill-buffers |
新分配的 Buffer 自动清零 |
| 15 | --track-heap-objects |
跟踪堆对象分配,供堆快照使用 |
| 16 | --prof-process |
处理 V8 生成的 profiler 输出 |
| 17 | --V8-options |
打印 V8 命令行选项 |
| 18 | --tls-cipher-list=list |
指定默认 TLS 加密套件列表 |
| 19 | --icu-data-dir=file |
指定 ICU 数据加载路径 |
| 20 | --watch |
文件变化时自动重启应用 |
| 21 | --watch-path |
监听指定目录或文件 |
| 22 | --env-file |
从 .env 文件加载环境变量 |
| 23 | --run |
运行 package.json 中定义的脚本 |
| 24 | --inspect |
启用调试器 |
| 25 | --inspect-brk |
启动调试器并在代码执行前暂停 |
| 26 | --enable-source-maps |
启用 source map,改善堆栈可读性 |
| 27 | --test |
运行 Node.js 内置测试运行器 |
| 28 | --input-type |
指定输入类型为 module 或 commonjs |
| 29 | --cpu-prof |
生成 CPU 性能剖析文件 |
| 30 | --heap-prof |
生成堆内存剖析文件 |
| 31 | --heap-prof-dir |
指定堆剖析文件保存目录 |
注意:--watch、--env-file、--run 属于较新版本才引入的选项,老版本 Node.js 上会直接报未知参数。动手前先 node -v 确认版本。
3 基本选项:日常敲得最多的几个
版本与帮助
node -v
node --help
-v 输出形如 v24.5.0。--help 会列出当前版本支持的全部选项,不同版本输出不同,遇到不确定的参数先查这里,比翻文档快。
直接执行代码:-e 与 -p
临时验证一段逻辑,不必新建文件:
node -e "console.log('代码号学习编程')"
node -p "10 + 20"
区别在于:-e 只求值,-p 会额外打印结果。-p 等价于 -e 外面包一层 console.log。做快速数学计算、验证正则、检查某个 API 返回值时,-p 特别顺手。
踩坑记录:
-e里的代码如果包含 shell 特殊字符(比如$、反引号),不同 shell 的转义规则不一样。Windows 的 cmd 和 PowerShell 对引号处理也不同。写复杂表达式时,用单引号包裹整体、内部用双引号,能减少很多莫名其妙的解析错误。
语法检查:-c
node -c example.js
只做语法解析,不执行代码。没有语法错误就静默退出,有错误才输出。适合在 CI 流水线里做快速门禁,比跑完整测试快得多。但它不检查运行时错误,变量未定义、模块找不到这类问题它发现不了。
交互式 REPL:-i
node -i
进入 Read-Eval-Print Loop,逐行输入逐行执行。适合调试小片段、探索 API 行为。默认情况下 Node.js 检测到非终端环境不会进 REPL,-i 强制打开。
预加载模块:-r
node -r ./config.js app.js
在入口脚本执行前先加载指定模块,遵循 require() 的解析规则。典型用途是初始化全局配置、注册 Babel 转译器、注入环境变量。
config.js 内容:
global.message = "代码号学习编程";
app.js 内容:
console.log(message);
执行 node -r ./config.js app.js 输出 代码号学习编程。
个人建议:
-r适合做轻量的启动前注入。但如果预加载逻辑变重,比如要连接数据库、初始化日志系统,更推荐把这些放到入口文件顶部显式 import,可读性更好,也方便做条件判断。隐式预加载用多了,新人接手时会找不到变量从哪来。
4 开发选项:监听、环境变量、脚本运行
--watch 与 --watch-path
node --watch app.js
node --watch-path=./src app.js
--watch 监听入口文件及其依赖,变化时重启进程。--watch-path 可以指定监听的目录或文件,粒度更细。
反思:
--watch在开发阶段确实省事,但要注意它不适合生产环境。生产环境应该用 PM2、systemd 或容器编排工具做进程管理,它们提供日志轮转、崩溃重启、集群模式等能力,--watch只解决文件变化重启这一个问题。
--env-file
node --env-file=.env app.js
从 .env 文件读取环境变量注入 process.env。以前这件事要靠 dotenv 包,现在原生支持了。
.env 文件:
DB_HOST=localhost
DB_PORT=5432
app.js 里直接 process.env.DB_HOST 就能读到。
踩坑经历:
--env-file不会覆盖已存在的系统环境变量。有一次我在服务器上设了NODE_ENV=production,本地.env里写NODE_ENV=development,结果读出来还是 production,排查了半天。记住:系统环境变量优先级更高。
--run
package.json:
{
"scripts": {
"start": "node app.js"
}
}
node --run start
直接运行 scripts 里定义的脚本。相比 npm run start,它少了一层 npm 的解析,启动略快。但功能上不如 npm scripts 完整,比如 pre/post 钩子、跨平台环境变量设置这些它不支持。
选型建议:小项目、简单脚本用
node --run够了。项目里已经有一套 npm scripts 工作流,继续用npm run,没必要混用两套。
5 调试选项:--inspect 与 --inspect-brk
node --inspect app.js
node --inspect-brk app.js
--inspect 启动调试器,默认监听 127.0.0.1:9229。Chrome 浏览器打开 chrome://inspect 就能连接,打断点、看调用栈、检查变量。
--inspect-brk 在代码执行前暂停,适合调试启动阶段的逻辑——比如模块加载顺序、初始化配置。普通 --inspect 下,进程会直接跑起来,你还没来得及连上,启动代码已经执行完了。
--enable-source-maps 配合使用,能把压缩后的堆栈映射回源码位置,TypeScript 项目或用了打包工具的项目尤其需要。
独到见解:很多人调试 Node.js 第一反应是
console.log。简单问题确实够用,但涉及异步调用链、闭包变量、事件循环顺序时,断点调试器能看到console.log看不到的东西。我建议把--inspect-brk加到常用命令列表里,遇到“明明应该执行却没执行”的问题时,直接断在启动点,一步步走,比猜快得多。
6 性能与剖析选项:--cpu-prof 与 --heap-prof
node --cpu-prof app.js
node --heap-prof app.js
node --heap-prof-dir=./profiles app.js
--cpu-prof 生成 .cpuprofile 文件,记录函数调用耗时,用 Chrome DevTools 的 Performance 面板打开分析。--heap-prof 生成堆快照,用来定位内存泄漏。--heap-prof-dir 指定输出目录。
相关选项还有:
-
--prof-process:处理 V8 的--prof输出,生成可读报告。 -
--track-heap-objects:跟踪堆对象分配,供堆快照使用。 -
--zero-fill-buffers:新 Buffer 自动清零,避免读到残留数据,代价是分配变慢。
经验:内存泄漏排查,
--heap-prof适合看“某一时刻内存里有什么”,--track-heap-objects适合看“对象是什么时候被分配的”。两者结合,先用 heap-prof 确认泄漏对象类型,再用 track-heap-objects 定位分配位置。CPU 热点分析同理,--cpu-prof先看哪个函数占时间最多,再针对性优化。
--max-old-space-size 虽然不在上面 31 项列表里,但和性能调优密切相关,用来设置 V8 老生代内存上限,单位 MB:
node --max-old-space-size=4096 app.js
大内存应用在容器里跑,经常需要显式设置这个值,否则 Node.js 可能按宿主机的内存来算,导致容器 OOM。
7 测试选项:--test
node --test
运行 Node.js 内置测试运行器,自动查找符合命名规则(*.test.js、*-test.js 等)的测试文件。不需要 Jest、Mocha 就能跑基础测试。
选型思考:内置测试运行器胜在零依赖、启动快,适合工具库、小型服务。但如果项目需要快照测试、mock 体系、覆盖率报告、watch 模式配合复杂断言库,Jest 或 Vitest 仍然更成熟。我的建议是:新项目如果测试需求简单,先用内置的,等它不够用了再迁移,迁移成本并不高。
8 运行时配置选项:--input-type 与 ICU/TLS
node --input-type=module -e "import fs from 'fs'"
--input-type 指定 -e 输入的代码按 ESM 还是 CommonJS 解析。默认是 CommonJS,要跑 ESM 语法就得显式指定。
--icu-data-dir=file 指定 ICU 数据路径,影响 Intl 相关 API 的行为。--tls-cipher-list=list 指定 TLS 加密套件列表。这两个偏底层,普通业务开发很少碰,做国际化或安全合规时才需要关注。
9 六类选项分类总览
把 31 个选项按用途归类,方便记忆和查阅:
基本选项:-v、-h、-e、-p、-c、-i、-r。做版本查看、代码执行、语法检查、REPL 交互、模块预加载。
开发选项:--watch、--watch-path、--env-file。提升开发效率,自动重启、加载环境变量。
调试选项:--inspect、--inspect-brk、--enable-source-maps。连接调试器、断点调试、改善堆栈可读性。
性能与剖析选项:--cpu-prof、--heap-prof、--heap-prof-dir、--prof-process、--track-heap-objects、--zero-fill-buffers、--max-old-space-size。CPU 热点分析、内存泄漏排查、内存上限设置。
测试选项:--test。运行内置测试运行器。
运行时配置选项:--env-file、--input-type、--enable-source-maps、--max-old-space-size、--icu-data-dir、--tls-cipher-list。定制运行时行为。
10 为什么值得花时间学命令行选项
第一,语法检查前置。 -c 能在执行前发现语法错误,CI 里加一道 node -c 门禁,比等测试跑完再报错快得多。
第二,调试能力不依赖 IDE。 服务器上、容器里、SSH 会话中,没有图形界面,--inspect 配合端口转发照样能调试。
第三,性能问题有据可查。 --cpu-prof 和 --heap-prof 给出的是数据,不是猜测。优化前先剖析,避免凭感觉改代码。
第四,终端操作效率更高。 改一行配置、跑一段验证代码、查一个版本号,敲命令比打开 IDE 再找菜单快。
11 本节课程知识要点
-
Node.js CLI 语法为
node [options] [script.js] [arguments],四个部分各司其职。 -
-e执行代码不打印结果,-p执行并打印,-c只检查语法不执行。 -
-r预加载模块遵循require()解析规则,适合轻量注入,重逻辑建议显式 import。 -
--watch适合开发环境,生产环境用专业进程管理工具。 -
--env-file不会覆盖系统环境变量,系统环境变量优先级更高。 -
--inspect-brk在启动阶段暂停,适合调试初始化逻辑。 -
--cpu-prof定位 CPU 热点,--heap-prof定位内存泄漏,配合使用效果更好。 -
--test是零依赖的内置测试方案,复杂测试需求仍可选用 Jest/Vitest。 -
新版本选项(
--watch、--env-file、--run)在老版本上不可用,使用前确认版本。
12 项目实例:一个完整的本地开发命令组合
假设你在开发一个 Express 服务,入口 server.js,环境变量放在 .env,源码在 src/ 目录。本地开发命令可以这样写:
node --watch-path=./src --env-file=.env --enable-source-maps server.js
-
--watch-path=./src:只监听源码目录,避免node_modules变化触发重启。 -
--env-file=.env:加载本地环境变量。 -
--enable-source-maps:如果用了 TypeScript 编译,堆栈能映射回.ts源文件。
排查内存问题时:
node --heap-prof --heap-prof-dir=./profiles server.js
生成的 .heapprofile 用 Chrome DevTools 打开,对比不同时间点的堆快照,找出持续增长的对象。
排查启动卡顿:
node --inspect-brk server.js
Chrome 连接后,在启动路径上打断点,逐函数步进,看时间花在哪。
13 个人踩坑与选型建议汇总
-
不要在生产环境用
--watch。它的重启机制没有日志轮转、没有优雅退出、没有集群支持。 -
-r预加载别塞太多逻辑。隐式全局变量会让代码难以追踪,新人接手成本高。 -
--env-file和系统环境变量的优先级要记牢。部署时系统环境变量会覆盖.env,本地测试通过不代表线上通过。 -
--inspect默认只监听本地。远程调试需要配合 SSH 端口转发,不要直接暴露 9229 端口到公网。 -
--max-old-space-size在容器里要显式设置。Node.js 默认按宿主机内存计算堆上限,容器限制 2G 但宿主机 64G 时,Node.js 可能用到远超 2G 才触发 GC,导致容器被杀。 -
内置测试运行器不是万能的。简单场景够用,复杂场景该上框架就上框架,工具是为人服务的,不必强求“零依赖”。
14 版本确认
文中示例输出基于 Node.js v24.5.0,你的实际版本号可能不同。--watch、--env-file、--run、--test 等选项在较老版本上不存在,执行前先 node -v 确认。