npm 为什么优先安装到当前项目目录?

优点

  • 不同项目依赖各成体系
  • 减轻包作者的 API 兼容压力

    缺点

  • 同一个依赖包在一台电脑上多次安装

    npm install 的安装机制

    Npm 的安装机制和背后的思想 - 图1
    两个注意的点,一个是检查 config,一个是构建依赖书。

    检查配置

    检查配置其实检查 .npmrc 的配置,在我们的电脑中存在多个 .npmrc 的配置。

  1. 项目中的 .npmrc

image.png
项目下 .npmrc 文件的优先级最高,可以给每个项目配置不同的镜像,项目之间的配置互不影响。
在项目的根目录下新建 .npmrc 文件,在里面以 key=value 的格式进行配置。

  1. registry=https://registry.npm.taobao.org
  1. 用户配置的 .npmrc(~/.npmrc)

image.png
可以通过npm config get userconfig命令获取用户配置的 .npmrc 文件在哪里。
image.png
可以通过npm config set命令设置用户级别的 .npmrc 配置。

  1. npm config set registry https://registry.npm.taobao.org

如果想删除可以直接编辑文件,或者使用npm config delete registry命令来进行删除。

  1. 全局配置的 .npmrc

image.png
可以通过 npm config get prefix命令获取全局配置的 .npmrc 文件的前缀地址,
image.png
记住是前缀地址,不是完整地址。完整地址是{$prefix}/etc/npmrc
但是如果你从来没有全局配置过,就不会存在这个文件。
也可以通过命令行来进行全局 .npmrc 文件的配置。

  1. npm config set registry https://registry.npm.taobao.org -g
  1. npm 内置的 .npmrc

npm 内置 .npmrc 配置文件和 npm 同级,所以可以通过获取 npm 的路径,来找到 npm 内置的 .npmrc 文件。
可以通过 which npm来获取npm 的路径,也就找到了npm 内置的 .npmrc 文件。
image.png

npm install 执行之后,首先,检查并获取 npm 配置,这里的优先级为:项目级的 .npmrc 文件 > 用户级的 .npmrc 文件> 全局级的 .npmrc 文件 > npm 内置的 .npmrc 文件。

构建依赖树

当前依赖项目不管其是直接依赖还是子依赖的依赖,都应该按照扁平化原则,优先将其放置在 node_modules 根目录(最新版本 npm 规范)。
在这个过程中,遇到相同模块就判断已放置在依赖树中的模块版本是否符合新模块的版本范围,如果符合则跳过;不符合则在当前模块的 node_modules 下放置该模块(最新版本 npm 规范)。

npm 缓存机制

通过 npm config get cache命令可以获取到缓存配置的路径。
image.png
打开缓存路径目录,在缓存目录下,存在一个很重要的目录,那就是_cacache目录,这个目录就是存在的缓存数据,在 npm v5 版本之后缓存都是存储在 _cacache目录下。
image.png
_cacache目录下有两个目录比较重要,是缓存的关键。

  • content-v2
  • index-v5

content-v2下面有很多目录,
image.png
我们随机找到一个文件,打开看看是什么。
image.png
发现是乱码,这里就需要用一个小技巧,把这些乱码解析出来。我们将乱码的文件改成压缩文件,文件扩展名改成 .tgz,然后在解压,得到的结果是 npm 包的资源。也就是说,在**content-v2**目录下存放的就是 npm 包的缓存资源。
image.png
我们再来看看 index-v5目录下存在的是什么?我们也随机打开一个文件,看看是什么?
image.png
文件里面有 hash 还有一些相关的信息,其实这些所有的内容构成了**content-v2**目录下 npm 包资源的引索。
有了缓存的 npm 包资源,也有了包资源的引索信息,那如何将缓存的资源加载到我们的项目中的了?
Npm 的安装机制和背后的思想 - 图14

注意,这里提到的缓存策略是从 npm v5 版本开始的。在 npm v5 版本之前,每个缓存的模块在 ~/.npm 文件夹中以模块名的形式直接存储,储存结构是:{cache}/{name}/{version}。

npm 离线安装

  • —prefer-offline:优先使用缓存数据,如果没有匹配的缓存数据,则从远程仓库下载。
  • —prefeer-online:优先使用网络数据,忽略缓存数据。
  • —offline:完全使用缓存数据,如果缓存中不存在,就按照失败。

    npm 不完全指南

    自定义 npm init

    npm 支持我们自定义 npm init,快速创建一个符合自己需求的自定义项目。npm init 命令本身并不复杂,它其实就是调用 shell 脚本输出一个初始化的 package.json 文件。那么相应地,我们要自定义 npm init 命令,就是写一个 node 脚本而已,它的 module.exports 即为 package.json 配置内容。 ```javascript const { exec } = require(‘child_process’);

const desc = prompt(‘请输入项目描述’, ‘项目描述…’); module.exports = { key: ‘value’, name: prompt(‘name?’, process.cwd().split(‘/‘).pop()), version: prompt(‘version?’, ‘0.0.1’), description: desc, main: ‘index.js’, repository: prompt(‘github repository url’, ‘’, function (url) { if (url) { exec(‘touch README.md’); exec(‘git init’); exec(git remote add origin ${url}); exec(‘git add .’); exec(‘git commit -m “first commit”‘); exec(‘git push -u origin master’); } return url; }), };

`` 使用命令npm config set init-module ~.npm-init.js来设置当我们执行npm init`时可以执行我们自定义的脚本。

利用 npm link,高效率在本地调试以验证包的可用性

npm link可以将模块链接到对应的业务项目中运行。
Npm 的安装机制和背后的思想 - 图15