feng xiaohan

npm

Node Pacakge Manager。Nodejs 的包管理工具。

类似于:PHP-Composer,Java-Maven,Python-pip,Rust-Cargo。

package.json

{
  "name": "ferhannah-cli",
  "version": "1.0.1", // 主版本号(大版本架构更新).次版本号(功能更新).bug修复
  "description": "ferhannah-cli 脚手架工具",
  // 模块化相关--
  "main": "index.js", // 用户用的时候找的路径
  "type": "module",
  "module": "",
  "browser": "",
  //---
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rollup -c rollup.config.js",
    "build-ts": "rollup --config rollup.config.ts --configPlugin typescript"
  },
  "keywords": ["Vite", "Vue3", "React", "CLI", "Ant Design", "Element Plus"],
  "bin": {
    // 配置可执行文件
    "ferhannah": "./bin/index.js"
  },
  "devDependencies": {}, // 开发时依赖
  "dependencies": {}, // 生产环境依赖
  "peerDependencies": {}, // 对等依赖,一般是插件人员和npm包开发人员使用;如果需要安装开发的插件必须下载其依赖的插件(对等插件)
  // npm 仓库配置信息--
  "repository": {
    "type": "git",
    "url": ""
  },
  "files": [], // 发布后能看到的文件
  "homepage": "",
  "author": "fxh",
  "license": "ISC"
  //--
}

npm install 原理

npm install 发生了什么?

安装的依赖会存放在根目录的 node_modules 下,默认采用扁平化的方式安装。在遍历依赖书时使用广度优先算法逐层处理每个依赖包中的依赖,直到所有的依赖都被处理完毕。在处理依赖时,npm 会检查该依赖的版本号是否符合依赖树中其他依赖版本要求,如果不合适则会尝试安装合适的版本。

如果发现需要相同依赖的不同版本,则会在需要该依赖的包下又新建一个 node_modules,再将依赖装进去。

  • 先检查 npm config;
  • 在当前目录下寻找.npmrc文件(项目级别),如果找到;
  • 再找当前用户的.npmrc文件(用户级别)
  • 再找全局的.npmrc文件(全局:AppData)
  • npm 内置的.npmrc文件(nodejs)
  • 检查是否有 package-lock.json 文件。
    • 有:则比较package.jsonpackage-lock.json内的依赖版本是否一致。
      • 不一致:会根据package.json下载并更新package-lock.json

        针对 npm 高版本,现在基本上都是。

      • 一致:检查缓存(之前是否安装过);
        • 有:直接解压到 node_modules。
        • 没有:去 npm 官网/镜像下载资源包,检查完整性,添加到缓存,更新package-lock.json文件;
    • 没有:获取包信息,构建依赖树和扁平化依赖,然后检查缓存;
      • 有:直接解压到 node_modules。
      • 没有:去 npm 官网/镜像下载资源包,检查完整性,添加到缓存,更新package-lock.json文件;

package-lock.json

可以锁定版本,记录依赖树的详细信息

  • version:包版本号;
  • resolved:包的下载地址;
  • integrity:验证包的完整性的哈希值(摘要);
  • dev:当前包是一个开发依赖包;
  • bin:包中可执行文件的路径和名称;
  • engines:包所依赖的 Nodejs 版本范围;

它还帮我们做了缓存通过 name + version + integrity 生成一个唯一的 key,这个 key 用于映射 npm 缓存文件(一般在 npm-catch 下),如果生成的 key 能与 integrity 对上,就会从映射文件中取出缓存的二进制包并解压出来使用

npm run 原理

npm run 发生了什么?(也就是指定 node 命令时)

nodejs 的所有命令都在 node_modules/.bin 下的可执行文件中。nodejs 支持跨平台、跨系统:

  • .sh:Unix、Linux 以及 MacOS 使用;
  • .cmd:cmd 执行文件(windows);
  • .ps1:powershell 执行文件(windows);

命令是在 package.json 中的 bin 内配置的。

  • 会在当前项目找 node_modules/.bin 中是否有该命令环境;
  • 再去全局的 node_modules 下找;
  • 再去环境变量中找;
  • 都找不到报错;

npm 生命周期

在执行 dev 之前和之后都有对应的生命周期使用,执行 dev 会自动调用 predev 和 postdev:

{
  "scripts": {
    "predev": "node prev.js",
    "dev": "node index.js",
    "postdev": "node post.js"
  }
}

应用场景:

  • predev:打包之前清除 dist 目录;
  • postdev:CI 脚本,发布之后自动将代码提交;

注意:dev 命令可以换成其他任何自定义命令,周期命令的配置也一样。

npm 私服

优势:

  • 可以离线使用;
  • 提高包的安全性,避免公共 npm 包出现漏洞;
  • 提高包的下载速度;

搭建

https://verdaccio.org/zh-cn/docs/installation/

npm install -g verdaccio

npm ci

npm install,但是是一种更干净的安装:

  • 要求 package-lock.json 等锁依赖版本的文件必须存在,且版本必须和 package.json 中要求的版本对应,否则会报错;
  • 在安装之前先把 node_modules 文件夹(下文可能会称为 modules)删除;
  • 无法单个安装;

场景:一般用于 docker 镜像构建时使用。