windows系统下npm升级的正确姿势以及原理
本文来自网易云社区
作者:陈观喜
网上关于npm升级很多方法多种多样,但是在windows系统下不是每种方法都会正确升级。其中在windows系统下主要的升级方法有以下三种:
-
首先最暴力的方法删掉nodejs和npm,然后在官网上Download 最新的msi,然后msi的安装会更新你的node和npm。
-
其次就是利用 npm install -g npm,这种方法是网上大多数人使用的方法,但是这种方法会有潜在的问题,我们在下面会介绍。
-
最后是利用npm-windows-upgrade来升级,参见How can I update npm on Windows?用管理员权限打开PowerShell,然后执行以下命令:
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Forcenpm install -g npm-windows-upgradenpm-windows-upgrade
其中,推荐使用第三种方法,这也是npm团队官方推荐使用的方法
准备工作
-
windows下的模拟终端:推荐使用powershell,经本人测试git bash 和mintty 终端模拟器在执行npm命令的时候会有问题,这两个终端执行的原理有兴趣的可以研究一下。
三种方法的比较
1.通过升级nodejs来升级
这种方法只需要删除nodejs和npm,然后下载最新的node进行安装就行。需要注意的是,删除npm的时候,需要把NODEJS目录下的npm文件夹和APPDATA的Roaming目录下的文件夹下的npm、npm-cache文件夹删除干净。
(NODEJS目录指的是你安装nodejs的目录,默认是C:\Program Files\nodejs, APPDATA的Roaming目录指的是C:\Users\<username>\AppData\Roaming,本人的APPDATA目录是C:\Users\chenguanxi\AppData\Roaming。windows系统的应用程序经常把数据和设置存放在用户的APPDATA目录,每个windows用户都有自己的APPDATA目录。)另外,APPDATA目录的用途参考What Is the AppData Folder in Windows?
2.npm install -g npm 方法(重点介绍)
在执行这个方法之前,先看一下我现在的node和npm版本:
$ node -v v8.11.3$ npm -v5.6.0
然后执行npm install -g npm得到以下结果:
$ npm -v 6.4.1
好像升级成功了?! 我们来看一下是不是真的吧nodejs目录的npm升级成功了:
打开NODEJS目录下对应的npm目录(C:\Program Files\nodejs\node_modules\npm) 的package.json文件:
还是5.6.0!!
然后打开APPDATA路径下的npm目录(C:\Users\chenguanxi\AppData\Roaming\npm),可以看到这里新增加了一个npm,打开其package.json文件可以得到:
在终端下执行npm -v得到的是APPDATA目录npm的版本结果。那么在执行npm命令的时候到底是执行哪一个npm呢?
从上图得出,不管执行哪一个路径下的npm,得到的结果都是一样的。 再深一步,我们先看一下NODEJS目录下的npm是怎么执行的。打开npm.cmd文件,了解这个文件到底执行了什么。
npm命令执行原理:
我们在npm.cmd文件加上一下log看一下相关的变量:
执行npm -v得到的结果:
'~dp0: ' C:\Program Files\nodejs\'NODE_EXE: ' C:\Program Files\nodejs\\node.exe'NPM_CLI_JS: ' C:\Program Files\nodejs\\node_modules\npm\bin\npm-cli.js'NPM_PREFIX_NPM_CLI_JS: ' C:\Users\chenguanxi\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js'NPM_CLI_JS: ' C:\Users\chenguanxi\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js'npm command ===:' C:\Program Files\nodejs\\node.exe C:\Users\chenguanxi\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js6.4.1
重要的注释(具体命令参考windows批处理(cmd/bat)编程详解):
-
%~dp0只可以用在批处理文件中,它是由它所在的批处理文件的目录位置决定的,是批处理文件所在的盘符:+路径,
-
设置npm-cli-js文件为批处理文件处理的目录对应的npm-cli.js文件关键:执行"%NODE_EXE%" "%NPM_CLI_JS%" prefix -g这个命令,也就是npm prefix -g这个命令(这个命令在下一小节说明),可以得到:C:\Users\chenguanxi\AppData\Roaming\npm。接着设置NPM_PREFIX_NPM_CLI_JS这个变量,如果存在NPM_PREFIX_NPM_CLI_JS,就把npm-cli.js设置为NPM_PREFIX_NPM_CLI_JS目录下的npm-cli.js文件
-
最后执行node.exe {对应的}\node_modules\npm\bin\npm-cli.js
npm prefix -g这个命令得到以下结果:C:\Users\chenguanxi\AppData\Roaming\npm具体命令执行的过程大概是通过读取prefix的配置,然后输出配置的结果
-
打开C:\Program Files\nodejs\node_modules\npm目录下的npmrc文件,可以看到只有一行的代码prefix=${APPDATA}\npm
-
${APPDATA}指的是node环境下的process.env.APPDATA变量
-
结果是:C:\Users\chenguanxi\AppData\Roaming
总结:
执行npm命令实际上是执行了node ${对应的}/npm-cli.js这个命令,关键是哪一个npm-cli.js文件:
-
总的执行过程就是要判断执行哪一个npm-cli.js文件。也就是说,如果存在全局prefix,那就执行全局prefix下的那个npm-cli.js 文件
-
也就是说执行npm命令,实际上是执行./node.exe ${对应的目录下}/node_modules\npm\bin\npm-cli.js
综上所述,npm命令执行的是nodejs目录下的npm命令。在弄清楚了npm是怎么执行之后,我们可以知道执行npm install -g npm 这个命令,其实是重新下载并安装了全局环境的npm包,然后通过prefix这个配置来链接到全局环境下的npm-cli.js文件,这个过程并没有对NODEJS目录下的npm版本进行任何修改。
所以,潜在的问题是当prefix配置被修改之后,npm执行的环境是未知的,不推荐这种通过链接到全局npm包的代理方式来升级npm。
3.npm升级的正确姿势应该是npm官方推荐的方法
参见How can I update npm on Windows?
用管理员权限打开PowerShell,然后执行以下命令:
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Forcenpm install -g npm-windows-upgradenpm-windows-upgrade
npm-windows-upgrade的执行过程:
1. ensureExecutionPolicy:检查用户的powershell 执行权限政策等2. ensureInternet:检查用户的网络状况3. chooseVersion: 让用户选择一个npm版本4. choosePath: 找到正确的npm安装目录5. upgrade:自动找到正升级npm的正确目录,保护和重新应用现有的配置,最终调用npm install -g npm
详细过程有兴趣的可以打开源文件看一下: 主要是以下三个文件:
-
C:\Users\chenguanxi\AppData\Roaming\npm\npm-windows-upgrade.cmd
-
C:\Users\chenguanxi\AppData\Roaming\npm\node_modules\npm-windows-upgrade\bin\npm-windows-upgrade.js
-
C:\Users\chenguanxi\AppData\Roaming\npm\node_modules\npm-windows-upgrade\lib\upgrader.js
也就是说执行npm-windows-upgrade,它会帮助我们自动找到正升级npm的正确目录,保护和重新应用现有的配置,最终调用npm install -g npm
总结
综上,在windows系统下升级npm的最佳方法是用npm-windows-upgrade来升级,这样可以保护并且重新应用到现有的配置,避免了潜在的问题。 通过以上实验过程有以下知识点总结:
-
npm命令是通过node npm-cli.js 命令来实现的
-
windows系统下,npm的全局包管理环境和node目录是分开的
以上有不对的地方,希望大家指正。
参考:
网易云免费体验馆,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】 追踪掠食者:地下灰产如何撸死创业公司?
【推荐】 从互联网+角度看云计算的现状与未来
【推荐】 测试周期内测试进度报告规范