# 前言
一直以来使用npm来安装node包依赖,但对命令行、环境变量和各自包管理工具都模棱两可,现在梳理一下。
安装 node.js 会自带 npm 这个默认的包管理器。
安装完后执行一下查看版本:
node -v
npm -v
命令和环境
首先,我们可以查看一下node的目录
where node
打开目录我们能看到有 node.exe、npm 等文件,这就是你在命令行执行时执行的文件程序;
其中npm 有 .cmd后缀的,还可能有 .ps1后缀 的,分别是 cmd命令 和 powerShell命令对应的执行文件;
你还可能看到npx相关的执行文件,这个是node@5.2版本之后添加的命令,后面再具体描述。
下面我们介绍一下window的环境变量
环境变量分别有系统环境变量(所有计算机用户共享)、用户环境变量、临时环境变量(只在当前会话有效);
- 右键点击“计算机”或“此电脑”,选择“属性”;
- 点击“高级系统设置”;
- 在“高级”选项卡下,点击“环境变量”按钮。
- 在这里你可以添加、编辑和删除系统和用户环境变量。
其中有一个环境变量叫 Path,双击打开是一个可编辑的列表,每一条记录都是一个目录,其中类似 %USERPROFILE% 是一个环境变量的引用;
你会发现node存放的目录就在这里,只有配置在这里,node、npm等才能成为全局命令;
接下来我们使用npm来安装依赖包
新建一个目录当中项目,并用cmd 打开它,我们安装一下 yarn
npm i yarn
安装完后发现项目下多了 package.json文件 和 node_modules文件夹,打开node_modules会有 yarn文件夹 和 .bin文件夹;
打开.bin 文件夹发现有yarn文件和yarn.cmd文件,此时我们尝试执行 yarn -v 发现报错: 'yarn' 不是内部或外部命令,也不是可运行的程序或批处理文件 ,因为我们并没有把这个 node_modules/.bin 添加到环境变量Path里面,故此不是全局命令。
那怎样才能够使用yarn呢,有以下几种方案:
-
执行
npm i yarn -g全局安装,此时会在node.exe所在文件夹这个全局目录中进行安装yarn包,这个目录下会多出yarn和yarn.cmd 等执行文件,node_modules里面也会多出yarn的文件夹; -
在项目的cmd下执行
node_modules\.bin\yarn.cmd -v进行指定文件执行 -
在项目的 package.json 文件中的
scripts部分添加一个脚本:
"scripts": { "yarn": "yarn" }
然后运行
npm run yarn -v
- 直接使用npx执行
npx yarn -v
这里讲下npx是什么:
npx 是 npm 5.2.0 及更高版本中附带的一个工具,它的目的是帮助你执行项目中安装的 npm 包中的可执行文件。npx 的执行规则如下:
- 本地查找: 首先,
npx会在当前目录或父级目录的node_modules/.bin目录下查找可执行文件。这样可以确保你能够在项目中执行安装在本地的 npm 包。 - 全局查找: 如果在本地没有找到相应的可执行文件,
npx会查找全局安装的 npm 包。 - 下载执行: 如果在本地和全局都没有找到,
npx会下载相应的 npm 包(如果不存在的话)到临时目录(定期清理)并执行其中的可执行文件。这就意味着你可以在不全局安装工具的情况下运行它们。 - 指定版本: 通过
npx package@version的形式,你可以执行特定版本的包,而不需要全局安装该版本。 - 执行 npm 脚本: 除了执行可执行文件,
npx还可以用于执行项目中的 npm 脚本,例如npx npm run scriptName。
OK,此时我们就可以使用yarn来执行了
yarn对比npm的优势是什么
yarn 和 npm 都是用于管理 JavaScript 包的工具,相比有以下优势:
-
性能(安装方式):
yarn在安装包时通常更快,因为它会并行下载多个包,而npm从 v7 开始支持并行安装,但默认情况下仍然是串行安装 -
离线模式(缓存机制):
yarn使用离线模式,可以在没有网络连接的情况下安装依赖,即使之前安装过的包,也可以通过缓存直接获取,不需要重新下载;而npm也有缓存机制,但是它的离线模式相对较弱。 -
可靠性(版本解析):
yarn使用精确的版本解析,可以确保在不同的环境中安装相同的依赖;而npm的版本解析相对宽松一些,这可能导致在不同环境中安装不同的依赖版本。 -
易于理解的 CLI:
yarn的命令行接口相对直观,提供了更一致和易于理解的命令;npm从 v7 开始 改进了 CLI,使其更加现代化和易用。
全局安装的话建议更改以下目录:
yarn global bin //查看全局bin目录路径
yarn config set prefix "自定义的全局bin目录路径" //设置yarn全局bin目录的路径,用npm安装的话其实可以无需理会
yarn global dir //查看全局global目录路径,就是全局node_modules所在目录
yarn config set global-folder "自定义的全局项目路径" //建议设置到非C盘
yarn cache dir //查看全局缓存路径
yarn config set cache-folder "自定义的全局cache目录路径" //建议设置到非C盘
关于镜像源
镜像源(Mirror Source) 是指在互联网上存在的一份主机的拷贝,通常用于提供更快速的访问速度。在软件开发中,特别是在包管理工具中,镜像源的作用是为了加速软件包的下载和安装过程。
cnpm 是淘宝提供的 npm 镜像源,使用 cnpm 可以加速包的下载,尤其对于在国内访问 npm 官方源较慢的情况。
你可以使用以下命令来安装 cnpm:
npm install -g cnpm --registry=https://registry.npmmirror.com
然后,你就可以使用 cnpm 代替 npm 来安装和管理包,例如:
cnpm install package-name
可以使用以下命令查看镜像源地址:
npm config get registry: 官方镜像是 registry.npmjs.orgyarn config get registry:官方镜像是 registry.yarnpkg.comcnpm config get registry:官方镜像是 registry.npmmirror.com
特别说明:
- 旧的淘宝镜像源 registry.npm.taobao.org 已经过期,请切换
- 不推荐cnpm,因为cnpm不会根据 package-lock.json 进行初始化安装,安装的包也不会更新package-lock.json,容易导致项目不稳定,还是推荐 nrm 进行镜像切换
使用nrm切换镜像源
nrm(npm registry manager)的主要功能是管理和切换 npm registry(镜像源),可以使用nrm test 命令可以测试当前所有 registry 的访问速度,再切换到速度快的镜像源。
npm install -g nrm
nrm test
nrm use 镜像名称(例如taobao)
当你使用 nrm use 切换源时,nrm 实际上是通过调用 npm config set registry 命令来更改 npm 的 registry 配置
如果你平常习惯使用yarn来执行命令,则可以使用 yrm,用法和nrm一样,但yrm会 同时更新npm和yarn的镜像源。
关于node多版本管理
当开发多个项目,但项目对应的node版本不一样时,我们可以使用nvm切换node版本。
- 点击 nvm下载地址,一般选择 最新版本 (latest标志)中
nvm-setup.zip进行下载安装就行。 - 安装完,环境变量会默认都给你添加,你可以前往环境变量查看多了 NVM_HOME 和 NVM_SYMLINK 这两个变量,并添加至Path变量列表中了。
- 需要切换安装node版本的镜像源的,打开安装目录下的 settings.txt 文件,node_mirror和npm_mirrord对应下载的镜像源地址,例如最新的淘宝镜像源地址:
node_mirror: https://npmmirror.com/mirrors/node/
npm_mirror: https://npmmirror.com/mirrors/npm/
nvm常见命令:
nvm list // 查看安装的所有node的版本
nvm list available // 查看当前可安装的版本,其中 LTS 表示长期稳定版本
nvm install xx.xx.xx // 安装xx.xx.xx版本的node,如果想安装最新版本则执行 nvm install latest
nvm use xx.xx.xx // 使用(切换到)xx.xx.xx版本的node
nvm uninstall xx.xx.xx // 卸载xx.xx.xx版本的node
nvm arch // 显示node是运行在32位还是64位。
nvm on // 开启node.js版本管理
nvm off // 关闭node.js版本管理
nvm proxy [url] // 设置下载代理。不加可选参数url,显示当前代理。将url设置为none则移除代理。
nvm node_mirror [url] // 设置node镜像。默认是https://nodejs.org/dist/。如果不写url,则使用默认url。设置后可至安装目录settings.txt文件查看,也可直接在该文件操作。
nvm npm_mirror [url] // 设置npm镜像。https://github.com/npm/cli/archive/。如果不写url,则使用默认url。设置后可至安装目录settings.txt文件查看,也可直接在该文件操作。
nvm root [path] // 设置存储不同版本node的目录。如果未设置,默认使用当前目录。
nvm是通过符号链接实现的,例如当你使用nvm install安装完某个版本A后,%NVM_HOME% 目录下会有A版本的文件夹;当你使用nvm use切换到A版本时,%NVM_SYMLINK% 这个符号链接会指向A版本的文件夹下;
而 %NVM_SYMLINK% 又因为添加到了环境变量的 Path变量 中,因此当你使用npm的时候调用的就是A版本文件夹下的npm文件,从而实现node的版本切换。
pnpm
pnpm( performant npm )指的是高性能的 npm
npm i pnpm -g
设置一下全局目录
pnpm config set global-bin-dir "pnpm全局bin目录" //如果用npm安装的,指向node目录路径,此路径下会存在可执行的pnpm二进制文件
pnpm config set cache-dir "pnpm的缓存路径" //建议设置到非C盘
pnpm config set state-dir "pnpm的安装状态信息路径" //尽量和缓存路径同一文件夹下
pnpm config set store-dir "pnpm的全局仓库路径" //一般会自动设置为磁盘的根目录的.pnpm-store文件夹,建议设置为非C盘的磁盘根目录下
pnpm config set global-dir "pnpm全局安装路径" //node_modules所在的目录,所有全局包都在这里
pnpm 通过硬链接(hark link)、符号链接(symbolic link,又叫软链接) + 全局存储(store)结合的依赖管理方式完全实现了依赖树结构的包管理方式
- 全局存储(store)集中管理依赖:pnpm 会在磁盘根目录下生成一个 .pnpm-store 文件夹,安装的依赖文件在这里都会缓存一份;
- 装包时命中缓存中有的依赖,会被硬链接到项目的 node_module 中的 .pnpm 文件夹 中;减少了 copy 的大量 IO 操作;
- 同一版本的依赖共用一个磁盘空间;不同版本依赖,只额外存储 diff 内容;
- 项目中的
node_modules/.pnmp通过<package-name>@<version>来实现相同模块不同版本之间隔离和复用,由于它只会根据项目中的依赖生成,所以不会hoist(提升)到根目录; - 项目
node_modules中已有依赖重复安装时,会被 软链接 到指定目录下
使用npm会出现的问题:
- npm没有全局存储store,不同项目下的依赖文件会重复创建;同一项目中,相同依赖不同版本的直接构建新的文件,不是只创建diff文件,会造成冗余的磁盘占用,拖慢装包速度;
- 由于存在 hoist 机制,下载依赖会优先放置在node_modules这个根目录,如果有版本冲突才放置在子目录(一般只对比直接依赖和开发依赖的版本),会造成幽灵依赖;
幽灵依赖:某个包没有在 package.json 被依赖,但是用户却能够引用到这个包;
而pnpm的实现方式完美的解决了上面的问题
下面科普下:
硬链接: 操作系统有自己对应的文件系统,而文件系统会给磁盘中每个文件分配一个编号(inode index);我们设置B硬链接A,则A与B的inode index是相同的,A与B都直接指向同一个磁盘文件。
符号链接(软链接): 类似于window的快捷方式;设置C软链接A,A与C的inode index是不相同的,其中C存放了A的路径名,可以根据这个找到A;假如A被删除,C依然存在,但指向一个无效路径;优点是可以跨域不同操作系统。
点击 硬链接与软链接 可以进一步了解
题外话
了解完上面的,可以去了解一些前端架构的解决方案了,如: