本文最初发布于Medium网站,经原作者授权由InfoQ中文站翻译并分享。
JavaScript是一种解释性语言,需要将其源代码提供给某些解释器才能运行。如果要使用Node.js运行JavaScript文件,通常会运行以下命令:
$ node yourfile.js
输入解释器(node)的名称后,你就明确告诉了外壳如何运行脚本。
但是这些知识可以放在脚本本身中,这样就可以像运行二进制文件一样直接运行它:
$ ./yourfile.js
仅当你对该文件有执行权限(例如,可以使用chmod u+x yourfile.js设置)并设置了正确的“Shebang”时,此方法才有效。
Shebang或hashbang(#!代码的英文发音)是文件的第一行,它告诉OS使用哪个解释器。它通常看起来像这样:
#!/absolute/path/to/the/interpreter [optional params]
Shebang是一项操作系统特性,可用于运行任何解释语言:Python、Perl等。对于Node.js,它可以(但通常不会)看起来像这样:
#!/usr/bin/node
只有Shebang在文件的第一行时,Node.js才会高兴地将其忽略为注释(即使它前面有空行或//comment行也不会起作用)。浏览器也会将其忽略(Chrome74+,FF67+)。
多数人在/usr/bin/node上都有一个Node.js二进制文件或符号链接。如果Node.js不在/usr/bin/node上,操作系统就会抱怨了。例如bash会说bad interpreter: No such file or directory script won’t execute。但有没有办法告诉操作系统使用Node.js运行脚本,而不用在乎它安装在哪里呢?
#!node
是没用的,因为Shebang需要绝对路径。
env主要用于在修改后的环境中运行命令。这里的重点是“命令”,因为env几乎总是位于/usr/bin/env,而“命令”可以是PATH上的任何内容。
如果我们不是写/usr/bin/node而是写/usr/bin/env node,我们就会告诉OS运行env,而env将运行node,最后node将依次执行脚本。
这是Node脚本最常见的Shebang:
#!/usr/bin/env node
但是,env还可以使用其他一些技巧。
将-S选项传递给env会使它解析之后发生的一切,从而打开一扇新的大门:将参数传递给命令。
例如,假设我们要运行带有特殊标志的node,以在运行当前文件时启用ESM模块。我们可以使用这个Shebang:
#!/usr/bin/env -S node --experimental-module
再举一个例子:如果我们想在运行当前脚本之前运行另一个脚本,可以使用Node的-r选项:
#!/usr/bin/env -S node -r ./my/other/file.js
或打开检查口:
#!/usr/bin/env -S node --inspect
请注意,如果你运行诸如nodeyourfile.js之类的脚本,Node.js将不会尝试解析Shebang中的参数,而只会忽略它。内核在运行文件之前使用Shebang来确定如何运行它。
还记得我们说过env可以在修改后的环境中运行命令吗?实际上这就是它名称的来源,而且它的功能非常强大。假设我们希望脚本以生产模式运行,我们可以设置NODE_ENV环境变量:
#!/usr/bin/env -S NODE_ENV=production node
否则,运行脚本时NODE_ENV将为undefined或使用用户终端的设置。 Node.js支持许多环境变量。例如,我们可以使用NODE_OPTIONS传递下列CLI标志:
#!/usr/bin/env -S NODE_OPTIONS=--experimental-modules node
如果我们希望脚本在运行时不访问用户终端上的任何环境变量,则可以使用-i标志来运行它,该标志代表“忽略环境”:
#!/usr/bin/env -S -i node
符号-相当于-i,所以我们也可以这样写:
#!/usr/bin/env -S - node
也许我们不想清除所有环境变量,但要屏蔽其中一些。例如DEBUG(如果你使用的是流行的debug包)。也许我们不希望脚本用户将DEBUG作为脚本运行时设置标志。那么我们使用-u标志代表未设置的环境变量。
#!/usr/bin/env -S -u=DEBUG - node
如果用户以DEBUG=* ./yourfile.js
运行脚本,他们将看不到任何调试信息,但你还是可以用DEBUG=* node ./yourfile.js
运行脚本,从而看到DEBUG输出。
有时你想锁定用于运行脚本的node版本。在NPM@3之前,我们可以使用engineStrict,但是该功能已移除,现在我们只能在package.json中设置engines,它可能位于脚本旁边也可能不在,取决于engine-strictconfig配置标志的设置。
但是有一种更简单的方法。由于node也是NPM包,并且npx允许运行任何NPM包,因此你可以编写:
#!/usr/bin/env -S npx node@6
这可能会在运行脚本后尝试下载请求的Node版本(因此,如果NPX缓存中不存在所请求版本的Node,则无法在没有互联网连接的情况下运行)。 提示:你可以使用process.version检查节点版本
没有规则说我们必须运行node。假设TypeScript和TS Node全局可用(npm -i g typescript ts-node),我们可以指定ts-node作为解释器:
#!/usr/bin/env ts-node
并让它作为TypeScript程序运行文件。 在这些示例中,文件都可以使用.js扩展名或你喜欢的其他任何文件类型,甚至可以没有扩展!
原文链接:《Node Shebang》
领取专属 10元无门槛券
私享最新 技术干货