macos 操作系统全局安装npm包,手动配置环境变量以及 npm 包命令行运行原理简述

3,504 阅读3分钟

前言

在macos,yarn 全局安装一个包后,例如 typescript 或者类似的工具,往往会直接使用工具暴露的全局命令去做一些事,例如 typescript 的 tsc 命令去编译ts文件,但是这个时候可能终端会报错,提示没有当前这个 tsc 的命令(zsh: command not found: tsc),这意味着缺少这个环境变量PATH,可能多数人第一次使用 macos 时会遇到这个问题,但是网上说法又比较多,可能 一些答案还会有版本问题,在解决的时候会比较麻烦。我自己有时也会忘了。 所以在这里记录下目前一些软件版本下的一个解决方法和前端工具在Node.js下运行命令行的相关原理。

🛩 希望能够帮助到大家以后在使用某npm包时遇到报错说某命令行不存在时,能从npm包运行原理的角度去找下问题,多一个思考的角度。

本文分两部分,第一部分主要是 macos 命令和环境变量相关说明,第二部分主要是npm包运行命令的一些原理说明。

1、command not found 找不到命令部分

场景

macos 操作系统 macOS Big Sur 下用的 iTem2 作终端工具。iTerm2 用的 zsh 作脚本工具。从 npm 上全局安装ts或者其他类似需要使用包自带命令的工具。安装完成后使用工具的全局命令 xxx 会提示 ”zsh: command not found xxx“

相关软件版本

软件版本
npm6.14.11
yarn1.22.10
macos12.0.1 (21A559)
vue-cli4.5.13

原因

首先说下 npm 包下载后运行命令的一个大概过程,因为导致问题出现的原因就在这个过程中。

从npm上下载包下来后,要使用里面相关的命令,大概过程是: 1️⃣ 执行这个命令。 首先,相当于先执行 which xxx 这个命令去查找可执行的xxx文件,

注意:

  • which指令会在环境变量$PATH设置的目录里查找符合条件的文件。
  • which 是linux命令,windows是无法直接执行这个命令的,windows是类似的从环境变量里找到对应的可执行文件去执行。

例如是 tsc 命令的话,相当于 先执行 which tsc 找到可执行的文件,如果是通过yarn全局安装,运行 which yarn 。结果会出现

/Users/username/.yarn/bin//tsc

这里其实是个软链接。 而这个软链接指向的是 Node.js 解析的相关文件。在我本地是

/Users/username/.config/yarn/global/node_modules/typescript/bin/tsc
👿 但是 which 找到这个文件的前提是,系统设置了相应的环境变量。

2️⃣ 如果没有设置环境变量,which 找不到这个可执行文件,自然是提示 command not found 了。 而 macos 系统默认的环境变量是

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

要想设置环境变量,首先需要找到存放对应的可执行文件的位置。 😼所以,下面讲解决方法。

解决方法

由于提示没有找到这个命令,意味着电脑系统缺少相关的环境变量。而在macos里,简单粗暴的配置环境变量的命令是

export PATH=$PATH:<PATH 1>:<PATH 2>:<PATH 3>:------:<PATH N>
  • <PATH 1> 代表 [可执行文件所在位置]
  • 在 macos 里,不推荐直接这么设置环境变量,这里是直接设置的系统环境变量,但更好的应该是设置用户级的环境变量,由于相关篇幅及概念过长,想了解的可以在下面的参考文章OSX系统修改$PATH环境变量里详细查看。
  • 如果环境变量设置弄乱了,有一种可以暴力清空的方式。 export PATH="" 清空所有系统环境变量 如果想通过 export PATH=$PATH:/test 这样单独去改某个环境变量是没用的,环境变量只会在末尾添加 /test ,而不是整个环境变量变成 /test

执行后会往系统环境变量里添加设置的环境变量。 如果添加了一个系统环境变量。 这个时候执行下面这个命令后

echo $PATH

可以看到后面添加多了一个路径。原本默认是只有前五个的(/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin)。(下面截图里,中间我误操作了一个环境变量,我打码了,所以中间才有那么长的空白,)6541636710236_.pic.jpg

注意:

  • 这里如果在另外一个终端程序打开,再执行 echo $PATH 查看。会发现没有后面添加的那串环境变量的。这里可能会让人误以为没设置某个目录的环境变量,所以这里说明一下。
  • 🔴 我之前为了测试环境变量,执行 sudo vim /etc/paths 进去编辑这个系统级的默认环境变量配置文件,删除了系统级别的环境变量,把 /usr/local/bin 这行给删掉了。结果后面 yarn 命令都运行不了了。这是因为在macos上全局安装yarn后,默认yarn 的软链是在 /usr/local/bin 上的。
  • 如果运行 export PATH=$PATH:<PATH 1> 这样的命令再打开终端或者重启也没效果,可以再执行 sudo vim /etc/paths 。往里面添加 yarn 全局下载的软链接地址。 或者,因为系统环境变量是 /usr/local/bin 所以可以直接将yarn全局安装包的位置修改到这个系统环境变量里。 执行下面这行命令
yarn config  set global-folder /usr/local/bin
  • 将 yarn 全局安装包的位置修改到这里,也可以直接使用包里的命令行(感谢群里猪崽大佬的提醒)

如果用npm全局安装包(在 macos,npm 全局安装包需要加上 sudo 获取管理员权限来安装),安装完之后会提示当前全局脚本所在命令行的位置。例如用npm全局安装ts,6511636689477_.pic.jpg 图里面的

/usr/local/lib/node_modules/typescript/bin/tsc

就是需要填写的文件位置 而如果想不用 npm i -g xxx 安装包之后再查看位置 也可以用命令行

// 查看安装目录路径
npm config get prefix

得到

/usr/local 

这个npm全局安装包的位置。 访问 /usr/local/lib/node_modules/ 找到对应包的名字的可执行目录的文件,如 typescript/bin/tsc

⁉️ 而如果是 yarn 全局安装包的话是不会有这些提示的 WeChatbeb48ae49a34bdcc489634337eb982a0.png

那么默认 yarn 全局安装包的位置在哪?
# 查看 yarn 全部安装包的文件夹位置
yarn global dir
# 查看 yarn 全局安装包的bin文件夹的位置
yarn global bin

yarn global bin 回车后结果如下 6531636698500_.pic.jpg

  • 如果把 yarn global bin 得到的结果 /Users/username/.yarn/bin 填进 export PATH=$PATH:<> 里后重启或者打开另一个终端发现命令行又无效,可以把这结果写进 /etc/paths 里保存,到时候所有通过 yarn 全局安装需要配置环境变量的几乎都不用配了。
  • 或者直接将 yarn 全局安装包的位置修改到系统默认环境变量位置上,就不用担心找不到包的全局命令了。
  • 把yarn global bin得到的目录/Users.username/.yarn/bin 或者里面软链点进去显示的真实路径/Users/username/.config/yarn/global/node_modules/typescript/bin/tsc 填进去export $PATH=PATH: 下次打开终端也还是会提示找不到命令。不知道原因是啥。

总结

要想让电脑终端可以使用一些自定义命令行,关键是要找到 .bin 文件夹,也就是可执行文件所在的文件位置。把里面的文件设置到对应操作系统的环境变量里。而本文只记录了一下 macos 里关于环境变量的一些简单踩坑和认识。


2、npm包运行的命令行部分

全局安装 npm 包时

通过 npm 全局安装一个包如 typescript 后,会解析安装包的 package.json 文件中的 bin 字段,在 Node.js 的安装目录下的 bin 目录下创建一个软链接,链接到当前包,软链接的名称是 bin 字段对象里的 key 字段,链接的内容是对象里的 value 字段, WeChatbcc9efaac4562f5e968f7e52ea44fa0f.png 而 value 指向的可执行文件的第一行要写

#! /usr/bin/env node

这行代码表示 用 Node.js 来解释执行。 #! 这个符号是个 Shebang ,这个符号通常在类Unix系统的脚本中第一行开头中出现,用于指明这个脚本文件的解释程序。所以这里表示从 /usr/bin/env 里找到 node 程序来解释执行这个脚本。直接运行 /usr/bin/env node 也相当于直接在命令行里运行 node。 可以发现,这里的 /usr/bin/ 刚好就是上面说到的系统的环境变量之一。

拿 tsc 举例,在终端里直接运行 tsc 相当于 node tsc.js 也相当于 /usr/bin/env node tsc.js。 而 tsc.js 明明是 js 文件,却可以直接执行,这就是 #! /usr/bin/env node 这行代码在通过 node 来解释执行这个文件。

  • 而且windows不支持Shebang,windows是通过文件的扩展名来确定使用什么解释器执行脚本的。
  • 如果 node 安装后不在系统默认的环境变量中,可以运行 npm config ls 查找node安装的位置, 然后将安装位置设置为环境变量

只在当前项目下可以执行的脚本

上面说的是全局安装一个包的情况下,直接在终端执行工具命令行的问题,而有些命令不是全局安装却也可以在当前项目下运行的,例如我们常用的 vue 的 vue-cli-service,这个命令不是在全局安装的却也可以在用vue-cli创建的项目下直接运行。

❓ 这是为什么呢

这就涉及到 npm 脚本了(详细原理可以查看引用文章里阮一峰老师的文章,这里只大概说一下跟包命令执行相关的部分)。 所谓 npm 脚本可以简单理解为写在 package.json 文件的 scripts 字段下的一些脚本。 而日常开发中使用到的命令行 npm run / yarn serve 大多相当于执行项目里的 vue-cli-service serve。而 npm run 有个神奇的功能,npm run 每次执行一个脚本的时候 ,都会自动新建一个 shell,而这个shell会将当前目录下的node_modules/.bin (点进去这里看能发现一堆可执行文件,如之前说到的tsc,vue-cli-service,还有现在流行的vite创建的项目里也会发现node_modules/.bin下有vite文件 )子目录加入环境变量,就是这里,可以让你一次性运行这些命令 (听起来很像npx?)

package.json 里的 bin字段 列出了可执行文件,表示你这个包要对外提供哪些脚本。 在这个包被 install 安装时,如果是全局安装 -g,bin 列出的可执行文件会被添加到 PATH 环境变量(全局可执行);如果是局部安装,则会进入到 node_modules/.bin/ 目录下。

总结

如果以后运行包里的命令行,遇到类似的提示 xxx 命令找不到,不存在之类的,可以从这个角度想想和查找问题出现的地方。

现代web前端因为有了Node.js,为前端大大赋能,各种工程化,模块化都依赖于这个环境上,而Node.js又因为npm脚本而暴露了很多方便快捷的用法。关键的使用都是靠找到对应的可执行文件去解释执行。

这里简单记录下 macos 下 npm 全局安装和 yarn 全局安装环境变量的问题。

以上就是本文的全部内容,下面是这篇文章查找资料时参考的部分文章。 如果上面有不对的,欢迎大佬们留言评论。 ❣️


参考文章