NPM IN DEEP

NPM 内部机制、核心原理和安装机制

Posted by 許敲敲 on December 28, 2020

NPM

NPM 内部机制和核心原理

  1. npm 不同于Ruby的Gem,Python的pip 全局安装,具备自己的泽设哲学。
  2. 即可全局,也可以local。

npm install安装机制

npm install 执行之后,首先,检查并获取 npm 配置,这里的优先级为:命令行设置的npmp配置 > env环境变量配置 > 项目级的 .npmrc 文件 > 用户级的 .npmrc 文件> 全局级的 .npmrc 文件 > npm 内置的 .npmrc 文件

然后检查项目中是否有 package-lock.json 文件。

如果有,则检查 package-lock.json 和 package.json 中声明的依赖是否一致:

  • 一致,直接使用 package-lock.json 中的信息,从缓存或网络资源中加载依赖;

  • 不一致,按照 npm 版本进行处理(不同 npm 版本处理会有不同,具体处理方式如图所示)。

如果没有,则根据 package.json 递归构建依赖树。然后按照构建好的依赖树下载完整的依赖资源,在下载时就会检查是否存在相关资源缓存:

  • 存在,则将缓存内容解压到 node_modules 中;

  • 否则就先从 npm 远程仓库下载包,校验包的完整性,并添加到缓存,同时解压到 node_modules。

最后生成 package-lock.json。

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

npm install 安装示意图

npm install 安装示意图

npm cli

CLI documentation

important :

  • npm ci :

npx

传统npm模式执行 eslint


npm install eslint --save-dev

# 项目根目录下
./node_modules/.bin/eslint --init
./node_modules/.bin/eslint yourfile.js

# npm scripts

模式

npxnpx eslint --init
npx eslint yourfile.js

npx 可以直接执行 node_modules/.bin 文件夹下的文件。在运行命令时,npx 可以自动去 node_modules/.bin 路径和环境变量 $PATH 里面检查命令是否存在,而不需要再在 package.json 中定义相关的 script。

npx 另一个更实用的好处是:npx 执行模块时会优先安装依赖,但是在安装执行后便删除此依赖,这就避免了全局安装模块带来的问题。

运行如下命令后,npx 会将 create-react-app 下载到一个临时目录,使用以后再删除

npx create-react-app cra-project

npm多源镜像

另外一个常见的问题就是 npm 镜像和依赖安装,关于 npm 镜像和依赖安装问题,归根到底还是网络环境导致的,一般情况下还是从网络层面解决问题。

网络方案解决不了,可参考博文:聊聊 npm 镜像那些险象环生的坑

npm ci

npm ci 就是专门为 CI 环境准备的安装命令,相比 npm install 它的不同之处在于:

  1. npm ci 要求项目中必须存在 package-lock.json 或 npm-shrinkwrap.json;

  2. npm ci 完全根据 package-lock.json 安装依赖,这可以保证整个开发团队都使用版本完全一致的依赖;

  3. 正因为 npm ci 完全根据 package-lock.json 安装依赖,在安装过程中,它不需要计算求解依赖满足问题、构造依赖树,因此安装过程会更加迅速;

  4. npm ci 在执行安装时,会先删除项目中现有的 node_modules,然后全新安装;

  5. npm ci 只能一次安装整个项目所有依赖包,无法安装单个依赖包;

  6. 如果 package-lock.json 和 package.json 冲突,那么 npm ci 会直接报错,并非更新 lockfiles;

  7. npm ci 永远不会改变 package.json 和 package-lock.json。

实践问题

开发应用建议提交 *.lockfile; 库文件需谨慎

  • 如果项目中只有 package.json 文件,npm install 之后,会根据它生成一个 package-lock.json 文件;

  • 如果项目中存在 package.json 和 package-lock.json 文件,同时 package.json 的 semver-range 版本 和 package-lock.json 中版本兼容,即使此时有新的适用版本,npm install 还是会根据 package-lock.json 下载;

  • 如果项目中存在 package.json 和 package-lock.json 文件,同时 package.json 的 semver-range 版本和 package-lock.json 中版本不兼容,npm install 时 package-lock.json 将会更新到兼容 package.json 的版本;

  • 如果 package-lock.json 和 npm-shrinkwrap.json 同时存在于项目根目录,package-lock.json 将会被忽略。

peerDependency

最佳实操建议

前最佳实操建议, 参考:

  1. 优先使用 npm v5.4.2 以上的 npm 版本,以保证 npm 的最基本先进性和稳定性。

  2. 项目的第一次搭建使用 npm install 安装依赖包,并提交 package.json、package-lock.json,而不提交 node_modules 目录。

  3. 其他项目成员首次 checkout/clone 项目代码后,执行一次 npm install 安装依赖包。

  4. 对于升级依赖包的需求:

    • 依靠 npm update 命令升级到新的小版本;

    • 依靠 npm install @ 升级大版本;

    • 也可以手动修改 package.json 中版本号,并执行 npm install 来升级版本;

    • 本地验证升级后新版本无问题,提交新的 package.json、package-lock.json 文件。

  5. 对于降级依赖包的需求:执行 npm install @ 命令,验证没问题后,提交新的 package.json、package-lock.json 文件。

  6. 删除某些依赖:

    • 执行 npm uninstall 命令,验证没问题后,提交新的 package.json、package-lock.json 文件;

    • 或者手动操作 package.json,删除依赖,执行 npm install 命令,验证没问题后,提交新的 package.json、package-lock.json 文件。

  7. 任何团队成员提交 package.json、package-lock.json 更新后,其他成员应该拉取代码后,执行 npm install 更新依赖。

  8. 任何时候都不要修改 package-lock.json。

  9. 如果 package-lock.json 出现冲突或问题,建议将本地的 package-lock.json 文件删除,引入远程的 package-lock.json 文件和 package.json,再执行 npm install 命令。