【记一忘三二】npm学习笔记

95 阅读8分钟

npm

npm使用流程

image-20240726233723015

npm install介绍

全局安装的包,不仅仅会在依赖包,还会将依赖包中可执行命令添加至环境变量中,一般放在.bin目录下

npm install

根据package-lock.json中包对应的的版本下载,如果没有package-lock.json文件,也会按照package.json写定的版本安装,比如vue的限制版本是^2.6.6,那么就只会安装2.6.6版本

npm install 包名

根据package.json中包对应的版本下载

这里需要注意,因为package.json中的版本是动态的,比如vue的限制版本是^2.6.6,那么在下载vue包时,就会下载符合^2.6.6版本限制的最新版本,也就是下载到^2.7.16"版本,并且

并且下载完还会更新package.json中的版本号

npm下载指定版本

# 下载最新版本
npm i md5@latest
# 下载指定版本
npm i md5@2.3.0

npm create vite实际做了什么?

npx create-vite

注:npm initnpm create是一样的

package.json文件配置

用于记录项目的npm包依赖信息或项目信息

主要作用

  • 用于管理本地项目
  • 用于发布开源项目,发布到registry仓库中

文件结构

{
  // 项目名称(必填)
  "name": "npm",
  // 项目版本(必填)
  "version": "1.0.0",
  // 项目描述
  "description": "",
  // 项目作者 (开源使用)
  "author": "",
  // 项目的开源协议(开源使用)
  "license": "ISC",
  // 项目发布成开源项目时,其他开发者如何搜索到该项目,也就是项目的关键词(开源使用)
  "keywords": [],
  // 项目是否是私有项目,如果是私有项目,就不能开源发布项目
  "private": true,
  // 项目的入口文件,在访问到该项目目录时,会首先访问该入口文件的地址
  "main": "./index.js",
  // 声明那些文件不去进行树摇判断处理
   "sideEffects":[],
  // 项目的脚本命令,通过npm run 命令的方式执行scripts中的脚本
  "scripts": {
    // 命令: 所需执行的脚本 npm run 命令名称
    // start、stop、
    "start": "node ./index.js"
  },
  // 项目中开发环境和生产环境都依赖的库,使用 `npm install 库名称 -S` 命令下载
  "dependencies": {
    /**
    * 库名称: 依赖版本
    * semver版本规范说明: `X.Y.Z`
    * X:大的版本发生改变,也就是新版本不兼容老版本的时候,比如Vue2和Vue3
    * Y:添加新的功能和API是改变的版本号
    * Z:修复bug时改变的版本号
    * 
    *
    * 版本号规定了在重新下载依赖时,下载依赖的版本
    * 依赖版本的前缀含义:
    *  无前缀:固定库的版本,库发生版本发生改变,并不会安装新的版本
    *  ~:代表固定X版本和Y的版本,只要有Z发生变化就会更新最新版本
    *  ^:代表固定X版本,只要有Y和Z发生变化就会更新最新版本
    *  *:始终更新最新版本
    *  
    */
    "element-plus": "^2.7.6"
  },
  // 项目中仅开发环境依赖的库,使用 `npm install 库名称 -D` 命令下载
  "devDependencies": {
    "webpack": "^5.92.1"
  },
  // 只会在开源项目中使用,表示该项目的依赖的其他的库,但不会被自动安装到项目中,需要用户手动下载安装
  /**
  * 为什么需要 peerDependencies,而不是放在 dependencies 或者 devDependencies 中?
  * 避免多次安装,而且这属于用户自行需要安装的库
  */
  "peerDependencies": {
    "vue": "^3.2.0"
  }
}

在开发项目时,dependenciesdevDependencies的区别不强,但是在开发第三方包时,要合理区分开,因为在其他人下载第三包时,会跟着下载dependencies中的依赖

导入lib包入口配置

默认:如果没有package.json配置或者package.json没有相对应的入口配置,就会使用当前文件夹index.js或者index.ts

main:一般常用的入口,也是保底入口,如果没有其他入口配置就会根据这个入口的配置,在浏览器和node中都可以使用

modlueEsModule规范的入口

browser:浏览器环境的入口

  • 浏览器环境使用import browser > modlue > main > 默认
  • node端使用requiremain > 默认
exports

node在16版本之后提出新的的入口配置,会直接覆盖前面的入口配置

{
  "main": "index.main.ts",
  "module": "index.module.ts",
  "browser": "index.browser.ts",
  "exports":{
    ".":{
      "require": "./index.module.ts"
    }
  },
}

比如说,上面的配置,在浏览器使用import导包,exports选项没有import入口配置,虽然有mainmodulebrowser选项,但是都不会采用,会直接使用默认入口

"exports":{
    ".":{
        "require": "./index.module.ts"
    },
    "./style":{
        "import":"./style.import.css",
        "require":"./style.require.css"
    }
},

exports还可以配置其他目录引入的情况,但需要主要,其他目录引入的规则,必须包在node_modules才有效

package-lock.json文件配置

该文件会自动在npm install命令自动生成

主要作用

  • 缓存以前下载的依赖,根据标识在本地找到对应的缓存包
  • 在其他开发者进行 npm install命令时,锁定具体的版本号
  • 开发者观察版本依赖的结构

文件结构

{ 
  // 项目名称
  "name": "npm",
  // 项目版本号
  "version": "1.0.0",
  // 项目package-lock.json的版本号
  "lockfileVersion": 3,
  // 项目的依赖关联采用的字段,如果是true,就会检验`dependencies`和`resolutions`两个字段
  "requires": true,
  // 项目的依赖
  "packages": {
    // 根依赖的入口
    "": {
      // 项目的名称
      "name": "npm",
      // 项目的版本号
      "version": "1.0.0",
      // 项目的开源协议
      "license": "ISC",
      // 根依赖的关联依赖
      "dependencies": {
        "less": "^4.2.0",
        "vue": "^2.7.7"
      }
    },
    "node_modules/vue": {
      // 依赖的版本号
      "version": "2.7.7",
      // 依赖的registry仓库的压缩包地址
      "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.7.tgz",
      // 当需要下载时,使用该字段的值和本地依赖缓存进行比对,如果相同就不在去registry仓库下载,而是直接使用本地缓存
      "integrity": "sha512-osfkncsGCWqtch+YWYxbqTNQ9hl/UQ6TFRkdmK/VqAjuMpxzr5QotFsYpmJ1AB1ez2LJeIKXDmtMkXUotMOTsA==",
      // deprecated 字段用于标记某个依赖项已经被废弃
      "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
      "dependencies": {
        "@vue/compiler-sfc": "2.7.7",
        "csstype": "^3.1.0"
      }
    },
  }

npm命令

卸载某个赖包

npm uninstall package

强制更新项目所有的包版本

npm rebuild

缓存

清除缓存

npm cache clean

查看配置

npm config list

查看包的基本信息

npm info md5

查看当前项目的所有包

npm list

检查项目包是否过期

npm outdated

执行命令

cmd窗口执行命令

image-20240727174441313

执行当前项目中node_modules中的命令

从上面的命令查找流程中,可以发现,如果想执行项目中安装依赖包可执行命令,因为依赖包在当前项目的node_modules目录中,也就决定了在项目根目录中执行不到这些可执行命令

进入命令目录

# 进入.bin目录
cd ./node_modules/.bin

# 执行命令
lessc -v

在当前目录中查找命令,就找到了

package.json文件中scripts添加脚本

"scripts": {
    "dev": "lessc -v"
},
# 执行命令
npm run dev

会首先在node_modules目录中查找可执行命令,如果找不到再去全局环境变量中查找

执行指令

npx指令

npx lessc -v

npx

npm link

npm link 安装全局包

a-p-dev 项目目录中执行 npm link,就会在全局安装 a-p-dev

npm link
  1. 在全局 nodejs node_modules 创建一个的a-p-dev软链接目录,指向原始 a-p-dev 项目原始的地址

  2. 扫描 h-run 文件夹,判断是否存在 bin 属性

{
    "name": "a-p-dev",
    "bin": {
        "a-p-dev": "bin/index.js"
    },
    "main": "bin/index.js"
}
  1. 在全局 nodejs 目录添加指定包名的 a-p-dev文件 和 a-p-dev.cmd 文件
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0

IF EXIST "%dp0%\node.exe" (
  SET "_prog=%dp0%\node.exe"
) ELSE (
  SET "_prog=node"
  SET PATHEXT=%PATHEXT:;.JS;=;%
)

endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\node_modules\a-p-dev\bin\index.js" %*s

npm uninstall [package-name] -g 卸载全局包

npm uninstall a-p-dev -g
  1. 删除全局 nodejs node_modules 下面的 a-p-dev软链接目录,并不会影响已存在的项目的引入

npm link [package-name]项目中引用全局包

npm link a-p-dev
  1. 在当前目录 node_modules 中添加 a-p-dev 目录的软连接,软连接到项目原始的地址,这里不是链接到全局nodejs node_modules 下面的地址

-

注意:package.json 并不会发生改变,也就是并没有添加 a-p-devdescription

{
  "name": "a-p"
}

const aPDev = require('a-p-dev');

console.log(aPDev);

npm unlink [package-name]项目中取消引用全局包

npm unlink a-p-dev
  1. 在当前目录 node_modules 中删除 a-p-dev 目录的软连接

pnpm

npm缺点

占用空间

多个项目node_modules中的依赖包是独立的,也就是会出现同一版本同一名称的依赖包出现在磁盘的不同位置,占用磁盘的储存空间

幽灵依赖

项目中可以访问到不属于当前项目所设定的依赖包

image-20240727215355116

软连接和硬链接

在项目中,明明只依赖了less一个包,但是因为less依赖其他包,也就会下载其他包,并且因为这些包都放在 node_modules目录中,那么在源代码就也可以使用,这显然设计不合理的

拷贝

拷贝

硬链接

硬链接 只是用于文件

软连接

软连接

也就是快捷方式,在点开软连接时,就会弹到打开源文件的地址 在require加载软连接时,也会追根溯源的加载到源文件

pnpm优点

节省空间

依赖包只会在磁盘中保存到统一位置,多个项目中相同的依赖包,通过硬链的方式加载

同一个依赖包的不同版本,只会记录不同的文件

速率高

在通过pnpm install安装第三方依赖包时,会先去本地依赖包的统一位置查询,如果存在就直接获取

pnpmworkspace

命令

  • 为指定模块安装外部依赖。
   pnpm --filter @h-cli/cli add -S  import-local
   
   pnpm --filter @h-cli/cli add -D  import-local
  • 根项目全局安装子项目
    pnpm add @h-cli/cli --workspace -w