node.js - 为什么我全局安装的 npm 包不能调用 ts-node?
问题描述
好的,我正在尝试创建一个供我自己使用的 CLI 工具,基本上它只是解析 hcitool 的标准输出(报告周围的蓝牙设备)。
该工具可以在这里找到:https ://github.com/lu4/hcitool-reader
该工具预计将使用ts-node
(ts-node 允许动态运行 TypeScript 代码)运行。
使用以下命令从本地磁盘全局安装时,我的包工作正常:
bash> npm i -g /path/to/local/disk/hcitool-reader/repository
可以通过执行以下命令来验证该工具(安装后):
bash> hcitool-reader
但是,如果我删除旧版本并从 NPM 安装相同的代码:
bash> npm uninstall -g hcitool-reader && npm i -g hcitool-reader
包开始抛出 node.js 语法异常,指出 typescript 语法错误(这是 ts-node 未正确注册的标志)。
bash> hcitool-reader
Trying to register ts-node with tsconfig.json found at:
/home/pi/.config/versions/node/v12.8.0/lib/node_modules/hcitool-reader/tsconfig.json
/home/pi/.config/versions/node/v12.8.0/lib/node_modules/hcitool-reader/src/index.ts:1
import 'reflect-metadata';
^^^^^^^^^^^^^^^^^^
SyntaxError: Unexpected string
at Module._compile (internal/modules/cjs/loader.js:811:22)
at Module._extensions..js (internal/modules/cjs/loader.js:879:10)
at Object.require.extensions.<computed> [as .ts] (/home/pi/.config/versions/node/v12.8.0/lib/node_modules/hcitool-reader/node_modules/ts-node/src/index.ts:465:14)
at Module.load (internal/modules/cjs/loader.js:731:32)
at Function.Module._load (internal/modules/cjs/loader.js:644:12)
at Module.require (internal/modules/cjs/loader.js:771:19)
at require (internal/modules/cjs/helpers.js:68:18)
at Object.<anonymous> (/home/pi/.config/versions/node/v12.8.0/lib/node_modules/hcitool-reader/bootstrap.js:15:20)
at Module._compile (internal/modules/cjs/loader.js:868:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:879:10)
这个错误的奇怪之处在于代码仅在位于 NPM 的全局包文件夹时才停止工作,在我的例子中:
/home/pi/.config/versions/node/v12.8.0/lib/node_modules/hcitool-reader
在所有其他情况下,从所有其他位置代码都可以正常工作。
问: ts-node 出了什么问题?
编辑
在我看来,这是一个ts-node
问题,我在他们的仓库中创建了一个问题,等待ts-node
团队的一些评论
解决方案
这是因为您编写了bin/launch.js
要运行的脚本node
,而不是ts-node
. 脚本的第一行是:
#!/usr/bin/env node
// ^^ launch with node.js
如果你想用 ts-node 启动它,你应该把它改成:
#!/usr/bin/env ts-node
壳牌sh-bang线
脚本的第一行就是通常所说的sh-bang行(有很多不同的拼写)。它是 sh/csh 兼容的语法,已被大多数常见的 shell 语言继承:bash/ksh/tcsh/tcl/node。
严格来说,它不是 javascript 语法,应该会导致语法错误,但如果它是第一行代码,node.js 会特别容忍它。它会导致 js 文件被解释为多语言源(源代码在不止一种编程语言中有效)。
shell(bash/ksh/tcsh 等)假定所有脚本都是用 shell 自己的语言编写的(bash 代表 bash,ksh 代表 ksh 等)。sh-bang 语法实际上使您的文件成为有效的 shell 脚本源文件。在所有常见的 unix shell 中,sh-bang 命令意味着:
评估此字符串,然后将此文件的其余部分视为注释,然后将此文件作为最后一个参数传递给正在评估的字符串。
因此,如果您的文件的第一行是:
#! /usr/bin/env wget https://stackoverflow.com/questions/57600624
该脚本将下载此页面。
/usr/bin/env
部分是运行env
加载当前用户环境的命令,然后执行该行的其余部分。我们运行的原因env
是因为默认情况下 sh-bang 语法不会加载您的用户环境,这意味着您需要传递绝对路径,node
或者ts-node
如果您在不同的发行版(ubuntu 与 redhat)上运行脚本,或者如果您安装node
或ts-node
不同的方式(apt-get vs nvm)。因此,首先调用env
确保您的$PATH
环境变量设置正确,并且在所有 Unix/类 Unix 系统env
中始终安装在/usr/bin
.
NPM 不是节点包管理器!
NPM 不是,也仍然不是专门设计为一个节点包管理器。是的,它有很多支持 node.js 的有用功能(有些像 node_modules 甚至在 node.js 中被硬编码)但它实际上并不关心你的软件是用什么语言编写的。它是你的操作系统的包管理器,就像apt
和yum
(或brew
为您的 Mac 用户)。因此,它对运行全局可执行文件没有特定于节点的支持 - 它仅取决于您的 OS/shell 已经支持的内容。在这种情况下,它取决于 sh-bang 线。
安装全局脚本时npm
不要使用start
package.json 中的命令。它直接运行您的脚本。这是因为它不是特定于节点的包管理器,因此它安装的可能是 Python 脚本或 shell 脚本或以汇编语言编写的二进制可执行文件。这就是为什么您需要确保您的"bin"
脚本通常可以由您的操作系统执行。
通常可执行意味着如果你这样做:
./bin/launch.js
那么你的操作系统可以像你系统上的所有其他程序一样执行它:node
,apt-get
等等git
。不正常会是这样的:
ts-node ./bin/launch.js
或者:
java -jar ./minecraft.jar