从npm cache clean --force使用来浅析npm模块的安装机制

一、解决 This is probably not a problem with npm. There is likely additional logging output above

  在执行 npm run serve 运行项目的时候报错:

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! lianshan@2.0.0 serve: `vue-cli-service serve`
npm ERR! Exit status 1
npm ERR!
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/.../_logs/..._10_01_084Z-debug.log

  如果出现这种报错情况,一般需要重新安装 node_modules 文件夹中的内容,但是在安装前,要把之前的内容都清空掉。

  其实大多数的主要问题是 package-lock.json 这个文件,一般使用 1、2、4 步就够了,如果不行在重新 1、2、3、4 步,因为使用了 第3步,在 $ npm install 安装会要点时间,相对较慢。

  解决步骤如下:

1、首先删除 node_modules,可以命令行删除,也可以手动右键删除文件夹。

2、删除 package-lock.json 文件

3、运行命令

npm cache clean --force

4、重新安装依赖:npm install

二、npm模块安装机制

1、npm install 安装之前,npm install会先检查node_modules目录之中是否已经存在指定模块。如果存在,就不再重新安装了,即使远程仓库已经有了一个新版本,也是如此。

  如果你希望,一个模块不管是否安装过,npm 都要强制重新安装,可以使用-f--force参数。

npm install <packageName> --force

2、如果想更新已安装模块,就要用到npm update命令。

npm update <packageName>

  它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。

3、那么npm update命令怎么知道每个模块的最新版本呢?

  答案是 npm 模块仓库提供了一个查询服务,叫做 registry 。以 npmjs.org 为例,它的查询服务网址是 https://registry.npmjs.org/

  这个网址后面跟上模块名,就会得到一个 JSON 对象,里面是该模块所有版本的信息。比如,访问 https://registry.npmjs.org/react,就会看到 react 模块所有版本的信息。

  它跟下面命令的效果是一样的。

npm view react

// npm view 的别名
npm info react
npm show react
npm v react

  registry 网址的模块名后面,还可以跟上版本号或者标签,用来查询某个具体版本的信息。比如, 访问 https://registry.npmjs.org/react/v0.14.6 ,就可以看到 React 的 0.14.6 版。

  返回的 JSON 对象里面,有一个dist.tarball属性,是该版本压缩包的网址。

dist: {
  shasum: '2a57c2cf8747b483759ad8de0fa47fb0c5cf5c6a',
  tarball: 'http://registry.npmjs.org/react/-/react-0.14.6.tgz' 
},

  到这个网址下载压缩包,在本地解压,就得到了模块的源码。npm installnpm update命令,都是通过这种方式安装模块的。

4、缓存目录

  npm installnpm update命令,从 registry 下载压缩包之后,都存放在本地的缓存目录。

  这个缓存目录,在 Linux 或 Mac 默认是用户主目录下的.npm目录,在 Windows 默认是%AppData%/npm-cache。通过配置命令,可以查看这个目录的具体位置。

PS D:\modb-front\modb-front> npm config get cache
D:\Program\nodejs\node_cache

  浏览一下这个目录,会看到里面存放着大量的模块,储存结构是{cache}/{name}/{version}

npm cache ls react

~/.npm/react/react/0.14.6/
~/.npm/react/react/0.14.6/package.tgz
~/.npm/react/react/0.14.6/package/
~/.npm/react/react/0.14.6/package/package.json

  每个模块的每个版本都有一个自己的子目录,里面是代码的压缩包package.tgz文件,以及一个描述文件package/package.json

  除此之外,还会生成一个{cache}/{hostname}/{path}/.cache.json文件。比如,从 npm 官方仓库下载 react 模块的时候,就会生成registry.npmjs.org/react/.cache.json文件。

  这个文件保存的是,所有版本的信息,以及该模块最近修改的时间和最新一次请求时服务器返回的 ETag 。

{
  "time":{
    "modified":"2016-01-06T23:52:45.571Z",
    // ...
  },
  "_etag":"\"7S37I0775YLURCFIO8N85FO0F\""
}

  对于一些不是很关键的操作(比如npm searchnpm view),npm会先查看.cache.json里面的模块最近更新时间跟当前时间的差距,是不是在可接受的范围之内。如果是的,就不再向远程仓库发出请求,而是直接返回.cache.json的数据。

5、模块的安装过程

  Node模块的安装过程是这样的:

1、发出npm install命令

2、npm 向 registry 查询模块压缩包的网址

3、下载压缩包,存放在~/.npm目录

4、解压压缩包到当前项目的node_modules目录

  注意,一个模块安装以后,本地其实保存了两份。一份是~/.npm目录下的压缩包,另一份是node_modules目录下解压后的代码。

  但是,运行npm install的时候,只会检查node_modules目录,而不会检查~/.npm目录。也就是说,如果一个模块在~/.npm下有压缩包,但是没有安装在node_modules目录中,npm 依然会从远程仓库下载一次新的压缩包。

  这种行为固然可以保证总是取得最新的代码,但有时并不是我们想要的。最大的问题是,它会极大地影响安装速度。即使某个模块的压缩包就在缓存目录中,也要去远程仓库下载,这怎么可能不慢呢?

  另外,有些场合没有网络(比如飞机上),但是你想安装的模块,明明就在缓存目录之中,这时也无法安装。

6、--cache-min 参数

  为了解决这些问题,npm 提供了一个--cache-min参数,用于从缓存目录安装模块。

  --cache-min参数指定一个时间(单位为分钟),只有超过这个时间的模块,才会从 registry 下载。

npm install --cache-min 9999999 <package-name>

  上面命令指定,只有超过999999分钟的模块,才从 registry 下载。实际上就是指定,所有模块都从缓存安装,这样就大大加快了下载速度。

参考文章:http://www.ruanyifeng.com/blog/2016/01/npm-install.html

posted @ 2021-03-30 18:57  古兰精  阅读(12216)  评论(0编辑  收藏  举报