从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 install
和npm update
命令,都是通过这种方式安装模块的。
4、缓存目录
npm install
或npm 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 search
或npm 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