编程崽

登录

一叶在编程苦海沉沦的扁舟之上,我是那只激情自射的崽

npm 功能使用

npm 功能使用

使用 node 开发时,使用的依赖包管理工具是 npm,只要使用 node 开发,基本都要用它下载依赖包到 node_modules 文件夹。

部分不常用的指令

功能 指令
清除全局缓存(切换node版本后可能需要) npm cache clean -f

npm 依赖更换源

使用npm下载依赖时,经常由于依赖资源的下载源在国外,导致下载缓慢、下载出错、经常超时等问题。

好在国内不少大公司在国内搭建了npm依赖的源镜像,每几分钟自动从npm源同步一次,所以我们可以使用这些国内的镜像,优化依赖下载。

淘宝支持的所有源,npm、node、electron等:https://npmmirror.com/

查看当前源

sh 复制代码
npm config get registry
# 默认是npm的地址 https://registry.npmjs.org/

切换其他源,比如淘宝源

sh 复制代码
npm config set registry=https://registry.npmmirror.com

指定单独某次安装依赖时使用的源

sh 复制代码
# 不修改全局默认的下载源,只是在这次安装vue时,使用淘宝源
npm i vue --registry=https://registry.npmmirror.com

注意:如果自己需要发布npm仓库,那么在进行 npm publish 时,源地址需要是npm的默认地址,也就是 https://registry.npmjs.org/

安装一些依赖时的报错

node-gyp 报错

使用npm过程中偶尔会遇到 node-gyp 相关的报红报错。

这是因为使用 npm 安装的某块依赖了 C++,这时就会隐式的安装 node-gyp,node-gyp 可编译这些依赖C++模块的模块。

node-gyp在首次编译时,会依赖Node源码,所以又会去下载 node 源码,但上面设置的淘宝镜像,是 npm install 是生效的,和下载 node 源码无关,导致网络问题又出现了。

这时就需要配置另一个参数了——disturl,他用来指定下载node源码时的地址。

sh 复制代码
# 查看当前的 disturl,将直接打印 undefined
npm config get disturl

# 设置国内镜像
npm config set disturl https://npmmirror.com/mirrors/node/

这样 node-gyp 的报错就去解决了。

node-sass 等其他报错

其他的依赖报错,大部分原因,可能是因为这个依赖需要从 github 下载一些东西。

比如在 node-sass@8.0.0 的源码搜索 github,可以找到以下一段代码:

js 复制代码
function getBinaryUrl() {
  var site = getArgument('--sass-binary-site') ||
             process.env.SASS_BINARY_SITE  ||
             process.env.npm_config_sass_binary_site ||
             (pkg.nodeSassConfig && pkg.nodeSassConfig.binarySite) ||
             'https://github.com/sass/node-sass/releases/download';

  return [site, 'v' + pkg.version, getBinaryName()].join('/');
}

可见,这个site变量的取值,会依次从前面的变量中取,如果都没有设置,就会设置为 github 的地址。

而 github 再国内又存在网络问题,这已经不是修改npm下载源能解决的问题了。

好在针对这些依赖,国内淘宝已经做了专门的优化,比如上面代码中依次取地址的 process.env.SASS_BINARY_SITE ,这个变量,我们就可以人为的设置:

sh 复制代码
npm config set sass_binary_site https://npmmirror.com/mirrors/node-sass/

注意,实测只有 npm版本 <= 8 时才可以设置,否则会报错说 sass_binary_site 非 npm 的 option,可以手动降级到 8 版本:npm i -g npm@8

然后再安装 node-sass,就可以下载成功了。

以此类推,其他的一些依赖报错也可以参考这个原因,可以查看其源码,查找变量名称,再从淘宝镜像网站https://npmmirror.com/查找地址来设置。

以下是已知的可设置的依赖和地址:

sh 复制代码
# node-sass
npm config set sass_binary_site https://npmmirror.com/mirrors/node-sass/

# sharp-libvips
npm config set sharp_dist_base_url https://npmmirror.com/mirrors/sharp-libvips/

# electron
npm config set electron_mirror https://npmmirror.com/mirrors/electron/

# mirrors
npm config set puppeteer_download_host https://npmmirror.com/mirrors/

# phantomjs
npm config set phantomjs_cdnurl https://npmmirror.com/mirrors/phantomjs/

# sentry-cli
npm config set sentrycli_cdnurl https://npmmirror.com/mirrors/sentry-cli/

# sqlite3
npm config set sqlite3_binary_site https://npmmirror.com/mirrors/sqlite3/

# python
npm config set python_mirror https://npmmirror.com/mirrors/python/

检索项目中未使用、缺失的依赖

如果接手一个被几经倒手的项目,或者成员众多且管理不善的项目,那package.json中的依赖可能会存在已经不使用的依赖,可以通过下面这个npm工具来检索:depcheck

先全局安装:

sh 复制代码
npm install -g depcheck

然后再项目目录使用:

sh 复制代码
depcheck

# or

depcheck 项目路径

会出现如下打印:

sh 复制代码
Unused dependencies # 下面是生产环境依赖中,未使用的依赖
* axios
* uuid
Unused devDependencies # 下面是开发环境依赖中,未使用的依赖
* babel-eslint
* eslint
Missing dependencies # 下面是缺失的依赖,以及项目中使用此依赖的文件位置
* moment: ./src/utils/logging/writers/BaseWriter.js

注意,上面我之所以会出现一个缺失的依赖,是因为这个依赖是其他依赖的依赖包,所以这个依赖被下载到了 node_modules 文件夹中,项目代码就能引入使用了,只是我的 package.json 中没有此以来的记录。

这种情况是需要避免的,只要项目中明文使用过了,就必须要在 package.json存在记录!所以需要手动安装一下缺失的依赖。

使用 nrm 管理 npm 的仓库地址源

上面是手动切换npm的源,这里的 nrm 是一个专门用来管理、切换 npm 源的工具,安装后即可使用,省的自己再记npm切换源的指令了。

1. 安装

sh 复制代码
npm install -g nrm

2. 查看 nrm 预置的不同源们

sh 复制代码
nrm ls

展示如下:

sh 复制代码
  npm ---------- https://registry.npmjs.org/
  yarn --------- https://registry.yarnpkg.com/
  tencent ------ https://mirrors.cloud.tencent.com/npm/
  cnpm --------- https://r.cnpmjs.org/
  taobao ------- https://registry.npmmirror.com/
  npmMirror ---- https://skimdb.npmjs.com/registry/

3. 常用指令

功能 指令
查看本地现有的所有源 nrm ls
切换为 taobao 源 nrm use taobao
添加新源 nrm add baidu http://www.baidu.com/
删除源 nrm del baidu
测试所有源的网速 nrm test
测试 npm 这个源的网速 nrm test npm

更新所有 npm 依赖

偶尔,自己使用最新版的vue或react,搭建了一个功能齐备的demo项目,打算以后有新项目要开发时,就拿这个demo项目作为底子,能省很多事。

但真有新项目时,可能已经过去了几个月,这个demo项目中的依赖们已经都有了新的小版本,这时要么忽略更新直接用;要么就是把所有依赖再npm install [依赖名字] 执行一遍,获取新版,这就有点小麻烦了。。。比较花时间。

这时就可以使用这个npm工具了 npm-check-updates

1. 安装

sh 复制代码
npm install -g npm-check-updates

2. 使用

sh 复制代码
# 在需要升级依赖的项目根目录,执行以下,可输出查看依赖的可升级列表
ncu

# 在需要升级依赖的项目根目录,执行以下,可自动进行依赖升级
ncu -u

安装来自 git 的依赖

比如有首页、用户中心页、功能页等三个项目,而这三个互不相同的项目,有一些模块却是共用的,比如全局样式、某个插件、或者 vue 或 react 的某个模块,这时就需要把几个项目通用的部分复用。

其中一个办法,就是把公用的部分,单独提交成一个 git 仓库,使用时就和一个 npm 依赖一样即可。

下面是 npm 安装来自于 git 的依赖的两种方式。

直接通过用户名安装

sh 复制代码
# 直接利用用户名与仓库名进行安装:npm install 【用户名】/【仓库名】,比如:
npm install baidu/echarts
# 或者为了提醒自己,加上github前缀进行区分
npm install github:baidu/echarts

通过地址安装

sh 复制代码
# 直接在 github 中,复制克隆项目的链接:npm install git+【链接】,比如下面
npm install git+https://github.com/niao-yu/l-test.git
# 或者把 https 改为 ssh,就可以使用 ssh 的方式安装了
npm install git+ssh://github.com/niao-yu/l-test.git

依赖包管理器 npm 和 yarn

基于 node 的项目,不可避免需要下载一些依赖包。

npm 是 node 自带的包管理器,cnpm 和 npm 功能基本一致,只不过修改了 npm 依赖包的下载位置,使用了国内源;

yarn 最初是为了解决 npm 的一些下载速度慢、依赖版本、缓存问题而设计的。

package.json 可以包含以下依赖类型:

  • dependencies:这是所谓的常规依赖,确切地说,是代码运行时所需要的(比如 React 和 immutableJS)。
  • devDependencies:这是开发依赖,就是那些只在开发过程中需要,而运行时不需要的依赖(比如 Babel 和 Flow) 。
  • peerDependencies:这是"同伴依赖",一种特殊的依赖,在发布包的时候需要。
  • optionalDependencies:这是可选依赖,意味着依赖是……可选的。这种依赖即便安装失败,Yarn也会认为整个依赖安装过程是成功的。
  • bundledDependencies:这是"打包依赖",在发布包时,这个数组里的包都会被打包(Bundle)。

大多数情况下只会用到 dependencies 和 devDependencies。
以上分类,只是给包在 package.json 中放的位置分类,便于分类管理,对实际使用是无影响的。

npm yarn 含义
npm install yarn install 安装所有 package.json 中的依赖
(N/A) yarn install --flat 安装所有依赖,但每个依赖只允许有一个版本存在
(N/A) yarn install --har 安装所有依赖,并
npm install --no-package-lock yarn install --no-lockfile 不读取或生成 yarn.lock 锁文件
(N/A) yarn install --pure-lockfile 不生成 yarn.lock 文件
npm install [pk] --save yarn add [pk] 添加依赖包到生产环境分类中 dependencies 中
npm install [pk] --save-dev yarn add [pk] --dev/-D 添加依赖包到开发环境分类中 devDependencies 中
(N/A) yarn add [pk] --peer/-P 添加依赖包到同伴依赖的分类 peerDependencies 中
npm install [pk] --save-optional yarn add [pk] --optional/-O 添加依赖包到可选依赖的分类 optionalDependencies 中
npm install [pk] --save-exact yarn add [pk] --exact/-E 默认情况下,使用相同主要版本的最新版本。例如, yarn add foo@1.2.3 将接受1.9.1版本,但是 yarn add foo@1.2.3 --exact 只接受1.2.3版本
(N/A) yarn add [pk] --tilde 安装具有相同小版本的包的最新版本,例如,yarn add foo@1.2.3 --tilde 将接受1.2.9,但不接受1.3.0。
npm install [pk] --global yarn global add [pk] 安装到全局依赖

注:

  • N/A:不适用,无此功能
  • [pk]:依赖包的名称

win10下使用cnpm报错

cnpm是当npm下载依赖由于网络问题而失败时的折中的一个下载工具,但当在win10下使用cnpm,可能会出现不能使用脚本的报错。

解决方案:

使用管理员身份运行 Windows PowerShell

输入 set-ExecutionPolicy RemoteSigned 回车,会出现选项,输入A(全是),回车

修改完成后,再输入 get-ExecutionPolicy ,回车,如果打印了 RemoteSigned 则说明修改完成,可以使用 cnpm 了。

引入依赖和 node_modules

使用 node 的都知道,使用依赖包管理器下载的所有依赖,都是放在一个叫做 node_modules 的文件夹中。

  • npm root:查看当前项目的 node_modules 目录路径,可能会展示父文件夹的 node_modules 路径,也可能展示一个不存在的 node_modules 路径(该创建但还没有创建)
  • npm root -g:查看当前 node 的 node_modules 目录路径
  • npm config get prefix:查看当前 node 的根目录路径

node_modules 基本说明

  1. 全局安装的依赖,放在 node 的安装目录中的 node_modules 文件夹,比如 pm2、vue-cli、cnpm、yarn 等等,我们都会全局安装

    注意,这些与其说是依赖包,不如说是 node 的功能包,因为这几个命令在安装后,可以直接在终端使用。

    这是因为这些命令在安装后,本体都放在 node 的 /lib/node_modules 中,但都会自动在 node 的 /bin 文件夹中做一个软链接,而 node 的 /bin 目录,又是在安装 node 时,就写入到了全局变量 $PATH 中的(可以使用指令 echo $PATH 查看),所以这些命令才能再终端中直接使用。

  2. 某个项目的依赖,放在当前项目下的 node_modules 文件夹中,这个就很多了,比如 jQuery、vue、react、mathjs 等等。

  3. 项目如果使用 git 进行管理,这个 node_modules 一般写在 .gitignore 中进行忽略,每次在新设备下拉了项目,再使用 node 的包管理器重新下载依赖。

  4. 当项目中引入某个依赖时,会优先从当前项目的的 node_modules 中查找该依赖,如果没有,则自动取全局的 node_modules 文件夹中查找,如果还没有,就会报错。

查找依赖的依赖链

当引入一个依赖时,会依次进行如下顺序查找:

  1. 引入的项目是 node 自带模块,比如 fs、http 等等,则直接返回 node 的该模块,不会去查找了

  2. 在当前项目位置查找 node_modules,如果有,则在里面找到依赖并引入

  3. 在父文件夹中查找 node_modules 并引入,以此类推,查找父文件夹中的 node_modules 并引入

  4. 查看是否存在环境变量 NODE_PATH(node 的全局依赖),如果有,则在该目录中查找依赖包,有则引入

    注意,NODE_PATH 应该是需要自己配置,一般是在 ~/.bash_profile 文件中添加一句 export NODE_PATH="【node 根目录】/lib/node_modules" # 指定 NODE_PATH 变量,然后执行 source .bash_profile 重载一下该文件来生效,有了这个配置,node 才有了全局依赖包的引入路径

  5. 报错

引入的方式为:const pack = require('pack')

找到依赖包后:

  1. 先检查改依赖包根目录是否存在 package.json 文件
  2. 检查文件中是否存在 main 字段
  3. main 字段会指定一个文件的路径,检查改文件是否存在
  4. 如果 maim 指定的文件存在,则会把这个文件作为最终引入的结果,返回给调用者
  5. 以上 4 项任意一项不符合预期,比如没有 package.json、maim 指定的文件不存在等,则会自动返回 index.js
  6. 如果 index.js 也不存在,报错

引入的方式为:const pack = require('pack/dist/abc.js')

找到依赖包后,直接在依赖包中查找 ./dist/abc.js 返回,如果该文件不存在,直接报错