npm包管理器
# npm包管理器
# npm简介
npm(全称 Node Package Manager,即“node包管理器”)是Node.js (opens new window)默认的、用JavaScript (opens new window)编写的软件包管理系统 (opens new window)。npm会随着Node.js自动安装。npm模块仓库提供了一个名为“registry”的查询服务,用户可通过本地的npm命令下载并安装指定模块。此外用户也可以通过npm把自己设计的模块分发到registry上面。
# npm的由来
npm完全用JavaScript (opens new window)写成,最初由艾萨克·施吕特(Isaac Z. Schlueter)开发。艾萨克表示自己意识到“模块管理很糟糕”的问题,并看到了PHP (opens new window)的PEAR (opens new window)与Perl (opens new window)的CPAN (opens new window)等软件的缺点,于是编写了npm。
# npm的发展历程
2009 年:npm 1.0 发布,随 Node.js 一起发布。
2014 年:npm 3 引入扁平化依赖管理(
node_modules结构优化)。2017 年:npm 5 引入
package-lock.json以确保依赖版本一致性。2020 年:npm 7 进一步改进依赖管理,支持 Workspaces 和自动安装
peerDependencies。
# npm执行流程
npm 的核心功能包括 包安装、依赖管理、版本控制,其实现原理大致如下:
包注册表(Registry)
- npm 默认使用 https://registry.npmjs.org/ 作为官方包仓库,存储所有公开的 JavaScript 包。
- 每个包都有一个唯一的名称和版本号,遵循 https://semver.org/ 规则。
依赖解析
- 当运行
npm install <package>时,npm 会:- 检查
package.json或直接查询注册表获取包信息。 - 递归解析依赖树,下载所有依赖包到
node_modules。 - npm 3+ 采用扁平化安装(尽量减少嵌套
node_modules),但可能仍有重复依赖。
- 检查
- 当运行
版本锁定
package-lock.json记录 精确的依赖版本,确保团队协作或部署时安装相同的依赖树。- npm 5+ 默认生成该文件,避免因语义化版本(如
^1.0.0)导致不同环境安装不同版本。
脚本执行
package.json中的scripts字段允许定义自定义命令(如npm start、npm test)。
参考资料:
- https://docs.npmjs.com/
- https://npm.github.io/how-npm-works-docs/npm3/
# npm的受控文件
npm 的核心配置和依赖管理依赖于以下文件:
| 受控文件 | 受控文件作用 |
|---|---|
package.json | 定义项目元数据(名称、版本、依赖、脚本等) |
package-lock.json | 锁定依赖版本,确保安装一致性 |
.npmrc | 配置 npm 行为(如 registry、代理、认证等) |
.npmignore | 指定哪些文件 不 发布到 npm 仓库(类似 .gitignore) |
过滤的无关文件:
node_modules/(由 npm 自动管理,不提交到 Git)npm-debug.log(调试日志,通常忽略)
# Command用例
# *login | 登录/登出账号
用于登录npm账号、登出账号、指定scope或registry。
# 登录当前用户
$ npm login
# login的别名
$ npm adduser
# 登录指定组织
$ npm login --scope=@组织名称
# 指定注册地址
$ npm login --registry=https://registry.npmjs.org
# 注销当前用户
$ npm logout
# 注销指定组织
$ npm logout --scope=@组织名称
# *init | 初始化项目
初始化生成一个包或工作区,支持跳过问卷、指定scope等。
# 初始化npm
$ npm init
# 指定组织并跳过问卷
$ npm init --scope=@组织名称 -y
也可以使用以下命令初始化工作区:
# 初始化一个工作区
$ npm init -w <dir>
# 通常来说都会以 packages/xxx作为工作区
$ npm init -w packages/pkg-name
还可以使用以下命令按模版初始化项目:
# 仅举例,无法使用
$ npm init pkg [<args>]
# 与下方命令一致
$ npm i -g create-pkg && create-pkg [<args>]
# 实际的命令转换其实是
$ npm exec create-pkg [<args>]
# 因为 npm exec|npm x|npx其实是相同的所以..
$ npx create-pkg [<args>]
# 可用例子
$ npm init vite vite-app
# *pub | 发布/取消发布
将包发布到注册表,支持指定标签、访问权限、删除已发布包。
# 模板
$ npm <pub|publish> {<tar>|<文件夹dir>}
# 基本发布示例(发布到latest标签)
$ npm pub
# 指定标签发布
$ npm pub --tag tag-name
# 发布公共包
$ npm pub --access=public
# 发布私有包
$ npm pub --access=restricted
# 删除已发布的包
$ npm unpublish <pkg-name>[@version] --force
# *install | 安装/卸载依赖包
安装、卸载依赖包,支持多种别名。
# 模板
$ npm <i|install|add> <pkg-name>
# 安装依赖
$ npm i <pkg-name>
# 卸载模板
$ npm <uninstall|remove|rm|r|un|unlink> <pkg-name>
# 卸载依赖
$ npm uninstall <pkg-name>
# *upgrade | 更新依赖包
更新所有或指定依赖包到最新版本。
# 全部更新
$ npm up
# 全局更新
$ npm up -g
# 指定包更新
$ npm up uniq
# *view | 查看包信息
显示包的详细信息或指定字段。
# 模板
$ npm <view|info|show|v> <pkg-name> <field># 查看全部信息
$ npm view uniq
# 查看指定字段
$ npm view uniq versions
# *cache | 缓存管理
添加、清除、验证、列出缓存。
add/添加: 将指定的包添加到本地缓存。此命令主要供 npm 内部使用,但它可以提供一种将数据显式添加到本地安装缓存的方法。
clean/清除: 删除缓存文件夹中的所有数据。请注意,这通常是不必要的,因为 npm 的缓存是自我修复的并且可以抵抗数据损坏问题。
# 添加缓存
$ npm cache add <pkg-name>
# 清除缓存
$ npm cache clean
# 验证缓存
$ npm cache verify
# 列出缓存
$ npm cache ls
# *docs | 快速打开包文档
快速跳转到包的文档或仓库主页。
$ npm docs <pkg-name>
$ npm home <pkg-name>
# bugs | 快速打开包issues
快速查看包的issues页面,便于反馈和解决问题。
$ npm bugs <pkg-name>
# repo | 快速打开包存储仓库
快速打开包的代码仓库。
$ npm repo <pkg-name>
# outdated | 列出可更新包
检查并列出可更新的依赖包。
$ npm outdated [<pkg-name>]
# JSON输出
$ npm outdated -j
# *config | 配置管理
查看、设置、删除npm配置,支持多层级。
npm 从命令行、环境变量、npmrc文件以及在某些情况下从package.json文件中获取其配置设置。主要是修改npm的源地址,npm环境变量等..
# 使用配置的优先级
Project > user > global > builtin
四个相关文件是:
- 每个项目的配置文件 [project]
- 每个用户的配置文件 [user]
- 全局配置文件 [global]
- npm 内置配置文件 [builtin]
# 查看所有配置
$ npm config list
# 查看指定配置
$ npm config get registry
# 设置配置
$ npm config set registry https://registry.npmjs.org
# 删除配置
$ npm config delete registry
# 编辑配置文件
$ npm config edit
# deprecate | 弃用包版本
指定包的某些版本弃用,安装时会提示警告。
# 模板
$ npm deprecate <pkg-name>[@ <version range>] <message>
# 弃用指定版本
$ npm deprecate pkg@1.0.0 "弃用说明:因为弃用,所以弃用"
# 弃用版本范围
$ npm deprecate pkg@"< 1.0.0" "1.0.0一下的版本都弃用了,望周知"
# *dist-tag | 标签管理
管理包的标签,便于多版本分流。
标签可用于提供别名而不是版本号。分流版本管理。
例如,一个项目可能会选择有发展的多个数据流,并使用不同的标签为每个数据流,如stable,beta,dev, canary。
拿Vue举个例子,Vue3已经在npm发布,但现在安装的Vue还是Vue2的,需要使用vue@next来安装Vue3的。next就是一个标签,Vue将Vue3的都发布在next这个标签内,如果不添加next会默认下载vue@latest
每个标签只有一个版本!版本库和标签是分离的。
如果发布时,不指定版本将会发布到latest,这时安装不@标签就会默认安装latest标签的版本
# 添加标签
$ npm dist-tag add <pkg-name>@<version> <tag-name>
# 删除标签
$ npm dist-tag rm <pkg-name> <tag-name>
# 查看标签
$ npm dist-tag ls <pkg-name>
# owner | 包管理员设置
查看/管理包的所有者。
# 查看管理员
$ npm owner ls <pkg-name>
# 添加管理员
$ npm owner add <user> <pkg-name>
# 删除管理员
$ npm owner rm <user> <pkg-name>
# team | 团队管理
管理组织团队及成员。
# 创建团队
$ npm team create <组织:团队名>
# 添加成员
$ npm team add <组织:团队名> <成员ID>
# 查看团队列表
$ npm team ls <组织名>
# 删除成员
$ npm team rm <组织:团队名> <成员ID>
# 删除团队
$ npm team destroy <组织:团队名>
# explore | 包命令作用域
进入已安装包的目录,生成子shell。
# 模版
$ npm explore <pkg>
# 示例
先安装一个局部的npm
$ npm i npm
然后进入这个npm的目录,并自动生成一个子shell
$ npm explore npm
# 打印npm版本,这时它会优先使用局部npm的版本
$ npm -v # 这时,这个npm就是局部的npm了
# 退出局部作用域
$ exit
最关键的用处其实在这里
假如依赖中有你的包,可以在当前项目中快速操作
# 发布模版
$ npm explore <my-pkg> -- npm pub
# 推送模版
$ npm explore <my-pkg> -- git pull origin master
# 基础示例
$ npm explore npm -- npm -v
# search | 搜索线上包
搜索npm仓库中的包。
$ npm search <pkg-name>
# 选项
# --description=false --registry=... --long -j|--json
| option | 说明 |
|---|---|
| --description=false | 不显示描述信息 |
| --registry=https://registry.npmjs.org | 修改查找的来源地址 |
| --long | 显示每个包更多的信息 |
| -j | --json | JSON格式输出 |
# link | 全局包与项目双向绑定
将包推向全局或将全局包链接到项目,实现双向绑定。
注意!!如果链接到某个项目,将node_modules删除了,那么对应的全局也会删除!!包括使用link的其他项目的此包也会删除
将包放到了npm的全局node_modules中是正常的全局的包,但使用link后会将全局的包和link到项目的包进行双向绑定关系。如果把一个全局的包link了多个项目,这些项目将共享一个包的全文件内容和状态。如果其中项目将这个包删除了,那么联动了全部项目,其他项目的这个包的内容也会被删除。
# 推向全局
$ npm link
# 链接到项目
$ npm link <pkg-name>
# 移除链接
$ npm unlink <pkg-name>
# ls | 列出已安装包
列出依赖包,支持多种选项。
$ npm ls [<pkg-name>]
# --link --depth 0 --long -j|--json --all
# *run | 运行自定义脚本
运行package.json中的脚本命令。
$ npm run <script>
# 工作区
$ npm run <script> -w <workspace>
# set-script | 设置自定义脚本
为package.json设置脚本任务。
$ npm set-script <script> <command>
# 工作区
$ npm set-script <script> <command> -w <workspace>
# *start/stop/restart | 启动/停止/重启项目
快捷运行start、stop、restart脚本。
$ npm start
$ npm stop
$ npm restart
# *test | 运行自定义测试
运行test脚本。
$ npm test
# *whoami | 查看登录用户名
显示当前登录用户的npm用户名。
$ npm whoami
# star | 收藏夹/星标
标记喜欢的包,查看/取消收藏。
# 模板 星标|星标列表|取消星标
$ npm <star|stars|unstar> [<pkg-name>]
$ npm star <pkg-name>
$ npm stars
$ npm unstar <pkg-name>
# *pkg | 操作package.json文件
查看、设置、删除package.json字段。
$ npm pkg get <key>
$ npm pkg set <key>=<value>
$ npm pkg delete <key>
# doctor | npm自检
检查npm安装状态。
$ npm doctor
$ npm ping https://registry.npmjs.org/
# edit | 快速编辑依赖
编辑已安装的包。
$ npm edit <pkg-name>
# explain | 查看包依赖关系
打印依赖关系链。
# 模版
$ npm <explain|why> <folder|specifier>
$ npm explain <pkg-name>
# prune | 删除无用包
删除无关的包。
# 模板
$ npm prune <pkg-name>
# 示例,不指定包 且打印json
$ npm prune -j
# dedupe | 删除重复包
优化依赖树,删除重复包。
搜索本地包树并尝试通过将依赖关系进一步向上移动树来简化整体结构,在那里它们可以被多个依赖包更有效地共享。
通过npm对比算法 (opens new window)后,删除重复的包
$ npm dedupe
# 别名
$ npm ddp
仅检查,不进行删除
$ npm find-dupes
# *pack | 生成tar包
从包创建一个tarball。
$ npm pack <pkg-name>
# *shrinkwrap | 生成Lock文件
将npm生成的package-lock.js或现有的node_modules生成一份package-lock.json
$ npm shrinkwrap
# *ci | 使用Lock快速安装
使用package-lock.json快速安装依赖。
npm ci在以下情况下会明显更快:
$ npm ci
# *hook | npm-HOOK
配置webhook,监控包/所有者/作用域变更。
钩子允许您配置 URL 端点,当任何受支持的实体类型发生更改时都会通知这些端点。钩子可以监视三种不同类型的实体:包、所有者和作用域。
要创建包挂钩,只需引用包名称。
$ npm hook ls [pkg]
$ npm hook add <entity> <url> <secret>
$ npm hook update <id> <url> [secret]
$ npm hook rm <id>
# install-ci-test | 快捷安装测试
安装并运行测试。
# 模版
$ npm <install-ci-test|cit> <pkg>
$ npm cit <pkg>
$ npm install-test <pkg>
$ npm it <pkg>
# token | 身份验证令牌
管理npm token。
# 查看已授权令牌
$ npm token
$ npm token list
# 创建token授权
$ npm token create
# 创建只读的授权
$ npm token create --read-only
# 创建白名单授权
$ npm tokken create --cidr=192.168.0.1/24,192.168.0.1/16
# 撤销授权
$ npm token revoke <id|token>
# bin | 命令存放位置
查看全局/当前项目命令存放路径。
# 打印全局存放位置
$ npm bin -g
# 打印当前项目存放位置
$ npm bin
# prefix | 输出项目位置
输出当前项目或全局npm位置。
# 当前项目位置
$ npm prefix
# 全局npm位置
$ npm prefix -g
# *root | 依赖根目录位置
打印node_modules目录。
$ npm root
$ npm root -g
# profile | 查看用户注册信息
查看/设置用户profile。
# 模板
$ npm profile <get|set|enable-2fa|disable-2fa> <key>{=<value>}
# 查看示例
$ npm profile get
# diff | 指定包进行diff对比
对比不同版本包内容。
| option | 说明 |
|---|---|
| --diff=pkg | 定义要在 中进行比较的参数,可多次设置 |
| --diff-name-only | 使用时仅打印文件名 |
| --diff-unified 3 | 要打印的上下文行数 |
| --diff-ignore-all-space | 比较中的行时忽略空格 |
| --diff-no-prefix | 不要在npm diff输出中显示任何源或目标前缀 |
| --diff-src-prefix | 要在npm diff输出中使用的源前缀 |
| --diff-dst-prefix | 要在npm diff输出中使用的目标前缀 |
| --diff-text | 将所有文件视为文本 |
# 模板
$npm diff --diff=<version-a> [...<paths>]
# 示例
$ npm diff --diff=uniq@0.0.2 --diff=uniq
$ npm diff --diff=uniq@0.0.2 --diff=uniq --diff-name-only
# *rebuild | 二进制包重新构建
重新编译C++插件等二进制包。
此命令npm build在匹配的文件夹上运行该命令。这在您安装新版本的 node 时很有用,并且必须使用新的二进制文件重新编译所有 C++ 插件。使用--ignore-scripts和安装时也很有用 --no-bin-links,可以明确选择要构建和/或链接 bin 的包。
如果提供了一个或多个包名称(以及可选的版本范围),则只会重建名称和版本与其中一个说明符匹配的包。
$ npm rebuild
$ npm rb <pkg-name>
$ npm rb canvas
# NPX介绍
# NPX简介
npx原本是npm团队独立出来的一个npm包,用于操作当前项目中的命令,后合并进npm。可用npm exec或npm x代替。
# *npx | NPX的工作方式
1.先搜索当前的项目node_modules/.bin中是否存在需要执行的命令
2.再到比本地的全局搜索是否存在需要执行的命令
3.如果项目和本地的全局都没有能够执行的命令,会缓存一个文件夹,下载命令去执行,但执行完成后将删除缓存的文件夹
# *npx | NPX命令行使用
$ npx <command>