NPM使用笔记
NPM(Node Package Manager) 是随同 NodeJS 一起安装的包管理工具,能解决 NodeJS 代码部署上的很多问题。
常见的使用场景有以下几种:
允许用户从 NPM 服务器下载别人编写的第三方包到本地使用。
允许用户从 NPM 服务器下载并安装别人编写的命令行程序到本地使用。
允许用户将自己编写的包或命令行程序上传到 NPM 服务器供别人使用。
通过输入 npm -v
来测试 npm 是否成功安装
npm install 安装模块
npm 的包安装分为本地安装(local)、全局安装(global)两种,从敲的命令行来看,差别只是有没有 -g
而已:
npm install -g 模块名称
全局安装,用于安装全局可用的命令行工具,例如 claude-code, hexonpm install 模块名称
本地安装,用于安装仅在某个项目(文件夹)内使用的依赖
npm install pkg
本地安装(默认)
本地安装(Local Installation) 是默认安装方式。
安装在当前项目(运行 npm
命令时所在的目录)目录下的 ./node_modules
文件夹中,如果没有 node_modules
目录会自动创建。
用于为特定项目提供依赖。依赖信息记录在项目的 package.json 文件的 dependencies
或 devDependencies
中。
安装之前,npm install 会先检查 node_modules 目录之中是否已经存在指定模块。如果存在,就不再重新安装了,即使远程仓库已经有了一个新版本,也是如此。
如果你希望,一个模块不管是否安装过,npm 都要强制重新安装,可以使用 -f
或 --force
参数: npm install <packageName> --force
特点:
- 项目隔离性: 每个项目拥有独立的 node_modules,依赖版本互不影响(避免版本冲突)。
- 版本控制: package.json + package-lock.json 锁定了精确依赖版本,保证不同环境(开发、生产)一致性。
- 依赖引用: 项目代码通过
require('package_name')
或ES6 import
引入本地安装的包。 - 启动脚本: 在 package.json 的
scripts
中定义的项目命令(如 npm start, npm test)可直接使用本地安装的 CLI 工具(无需全局安装)。 - 适用场景: Web 框架(React, Vue, Angular)、功能库(Lodash, Axios)、构建工具(Webpack, Babel - 作为项目依赖时)、测试库(Jest, Mocha)等。
npm install -g pkg
全局安装
通过 -g
参数指定 全局安装(Global Installation)
安装在系统全局目录中(与具体项目无关)。
核心目的是为了安装供命令行(CLI)工具在终端/命令行中全局使用。
通过 npm root -g
命令可查看全局安装路径,例如:
/opt/homebrew/lib/node_modules
Mac 上/usr/local/lib/node_modules
Unix 上%AppData%\npm\node_modules
Windows 上
特点:
- 全局可用性: 安装后,其提供的命令行命令可在系统任何路径下执行(需确保全局安装目录在系统的 PATH 环境变量中)。
- 非代码依赖: 在项目代码中不能通过 require 或 import 引入全局安装的包(除非项目本地也安装了)。
- 版本单一性: 整个系统通常只有一个版本,可能导致不同项目对全局工具版本要求不同时产生冲突。
- 适用场景: 提供终端命令的工具包
典型的全局工具包括:
- 脚手架工具:create-react-app, vue-cli, @angular/cli, expo-cli
- 构建/任务工具:gulp-cli, grunt-cli
- 包管理工具:yarn, pnpm (可以用npm安装它们自身)
- 实用工具:nodemon (自动重启Node应用), http-server (快速启动静态服务器), typescript (tsc命令)
- 跨项目工具:eslint, prettier (若需全局使用其CLI)
npm install -g npm@latest 升级全局npm版本
全局升级 npm 自身的版本到最新版
npm install -g npm@latest
使用 package.json
npm 5.0.0 及以上版本中,npm install <package_name>
命令默认就会将依赖包及其版本添加到 package.json 文件中的 dependencies 部分。
npm install 模块
安装指定模块,从 npm 5 开始,npm install <package_name>
自动等效于 npm install <package_name> --save
这意味着不需要显式添加 --save
选项,npm 就会把依赖写入 package.json
npm install 模块 --save
安装好后写入 package.json 的 dependencies 中(生产环境依赖)
npm install 模块 --save-dev
安装好后写入 package.json 的 devDepencies 中(开发环境依赖)
npm install <Module Name> --save
安装的同时,将信息写入 package.json 中。
项目路径中如果有 package.json 文件时,直接使用 npm install
方法就可以根据 dependencies 配置安装所有的依赖包
npm install --unsafe-perm
就是说 npm 出于安全考虑不支持以 root 用户运行,即使你用 root 用户身份运行了,npm 会自动转成一个叫 nobody 的用户来运行,而这个用户几乎没有任何权限。这样的话如果你脚本里有一些需要权限的操作,比如写文件(尤其是写 /root/.node-gyp ),就会崩掉了。
为了避免这种情况,要么按照 npm 的规矩来,专门建一个用于运行 npm 的高权限用户;要么加 –unsafe-perm 参数,这样就不会切换到 nobody 上,运行时是哪个用户就是哪个用户,即使是 root。
一劳永逸的方法:npm config set unsafe-perm
针对当前用户的npm config -g set unsafe-perm
全局的
https://docs.npmjs.com/misc/config#unsafe-perm
permission denied 问题
npm install 的时候,经常会碰到一个非常匪夷所思的错误,那就是:即使使用了 sudo,也可能会报权限错误 permission denied。
例如 sudo npm update hexo
时
$ sudo npm update hexo
Password:
> fsevents@1.2.9 install /Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents
> node install
node-pre-gyp WARN Using needle for node-pre-gyp https download
node-pre-gyp WARN Pre-built binaries not installable for fsevents@1.2.9 and node@10.4.0 (node-v64 ABI, unknown) (falling back to source compile with node-gyp)
node-pre-gyp WARN Hit error EACCES: permission denied, mkdir '/Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents/lib'
gyp ERR! configure error
gyp ERR! stack Error: EACCES: permission denied, mkdir '/Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents/build'
gyp ERR! System Darwin 17.7.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "--fallback-to-build" "--module=/Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" "--module_name=fse" "--module_path=/Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64" "--napi_version=3" "--node_abi_napi=napi" "--napi_build_version=0" "--node_napi_label=node-v64"
gyp ERR! cwd /Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents
gyp ERR! node -v v10.4.0
gyp ERR! node-gyp -v v5.0.3
gyp ERR! not ok
解决方法:
在npm install的时候,同时使用sudo
和--unsafe-perm
sudo npm install --unsafe-perm
$ sudo npm install --unsafe-perm
Password:
> fsevents@1.2.9 install /Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents
> node install
node-pre-gyp WARN Using needle for node-pre-gyp https download
[fsevents] Success: "/Users/si.ma/git/madaimeng_backup/node_modules/hexo-fs/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" is installed via remote
> fsevents@1.2.9 install /Users/si.ma/git/madaimeng_backup/node_modules/nunjucks/node_modules/fsevents
> node install
node-pre-gyp WARN Using needle for node-pre-gyp https download
[fsevents] Success: "/Users/si.ma/git/madaimeng_backup/node_modules/nunjucks/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" is installed via remote
added 138 packages from 35 contributors and audited 7136 packages in 7.598s
found 6 vulnerabilities (2 low, 3 moderate, 1 high)
run `npm audit fix` to fix them, or `npm audit` for details
sudo npm install 时,报错 permission denied 的解决方案
https://newsn.net/say/sudo-npm-install-permission.html
node_modules/.bin 模块的可执行文件
当通过 npm 安装一个包时(无论是 dependencies 还是 devDependencies),如果这个包提供了一个可以在命令行中调用的可执行文件(通常在其 package.json 中有 “bin” 字段声明),那么 npm 就会在项目的 node_modules/.bin 目录下创建指向这些可执行文件的符号链接(Symlinks)(在 Windows 上可能是 .cmd 或 .ps1 文件)。
npm cli
蕾西 npm i 安装依赖,但是严格按 package-lock.json 安装,适用于 CI/CD 或生产环境
完全依赖 package-lock.json,不修改它
npm list 查看安装包
npm list 查看本地已安装模块
npm list --depth=0
查看本地安装包–depth
表示深度,我们使用的模块会有依赖,深度为零的时候,不会显示依赖模块
npm list --depth --global
查看全局安装包
npm list -g 查看全局已安装模块
npm list –depth=0 仅查看直接依赖
仅列出项目直接依赖
npm root -g 查看全局安装路径
npm root -g
/opt/homebrew/lib/node_modules
npm update 更新模块
npm update <Module Name>
它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。
npm update <package>
可以把当前目录下 node_modules 子目录里边的对应模块更新至最新版本。npm update <package> -g
可以把全局安装的对应命令行程序更新至最新版。
npm uninstall 删除模块
删除全局模块npm uninstall -g <package>
删除本地模块npm uninstall 模块
删除本地模块时你应该思考的问题:是否将在 package.json
上的相应依赖信息也消除?npm uninstall 模块
:删除模块,但不删除模块留在package.json中的对应信息npm uninstall 模块 --save
删除模块,同时删除模块留在package.json中dependencies下的对应信息npm uninstall 模块 --save-dev
删除模块,同时删除模块留在package.json中devDependencies下的对应信息
例如
sudo npm uninstall hexo-generator-search --save
Password:
removed 1 package and audited 7132 packages in 4.202s
found 6 vulnerabilities (3 low, 2 moderate, 1 high)
run `npm audit fix` to fix them, or `npm audit` for details
npm search 搜索模块
npm search <Module Name>
npm prune 清理无效包
手动删除 package.json 中的依赖后,执行 npm prune
可删除所有 package.json 中不存在的包
package.json
package.json 中最重要的属性是 name 和 version 两个属性,这两个属性是必须要有的,否则模块就无法被安装,这两个属性一起形成了一个 npm 模块的唯一标识符。
package.json 开发者声明的依赖蓝图
package.json 是由开发者手动维护的,通过 npm install <package> --save / --save-dev
命令写入或更新,或者直接编辑
package.json 声明了需要哪些包以及愿意接受的大致版本范围,但并不锁定确切的版本。
package.json 主要关注顶级依赖(直接依赖)。
package.json 的目的:
- 列出项目直接依赖的包(在 dependencies、devDependencies、optionalDependencies 或 peerDependencies 中)。
- 定义项目元数据: 包含项目名称、版本、描述、入口点、脚本命令(scripts)、作者信息、仓库地址等。
- 指定兼容版本范围: 使用 语义化版本 SemVer 范围(如 ^1.2.3, ~1.2.0, >2.0.0, 2.x)来定义你的项目能接受的依赖包版本。
例如:
{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.18.0", // 声明需要 express,兼容 4.18.0 到 5.0.0(不含)之间
"lodash": "~4.17.21" // 声明需要 lodash,兼容 4.17.21 到 4.18.0(不含)之间
},
"devDependencies": {
"eslint": "^8.0.0"
}
}
package-lock.json 精确依赖树的权威快照
package-lock.json 用于描述整个依赖树:精确到每一个直接依赖和所有层级的间接依赖。
package-lock.json 是由 npm 自动生成和维护的,永远不要手动编辑 package-lock.json 它由 npm 在运行 npm install
或 npm install <package>
安装更新依赖时自动生成或更新。
package-lock.json 精确描述了当前 node_modules 文件夹中所有内容的确切状态,像一个时间点的详细快照。
package-lock.json 只包含确切的版本号(如 “version”: “4.18.2”),没有任何语义化范围符号(^, ~)。
package-lock.json 的目的:
- 锁定依赖树: 精确描述 node_modules 目录中实际安装的每一个包的确切版本(包括所有的直接依赖和嵌套的间接依赖/传递依赖)。
- 确保一致性: 是 npm 实现确定性安装和依赖一致性的核心。它保证在任何时候(不同的机器、不同的时间点)、任何人运行
npm install
时,只要存在有效的package-lock.json
就会安装完全相同的依赖树。 - 描述依赖关系结构: 不仅仅记录版本,还记录包从哪里下载(resolved URL)、包的完整性校验和(integrity hash),以及包之间的依赖关系结构。
package-lock.json 对依赖安装/更新的影响
当 package-lock.json 存在时
npm install
会忽略 package.json 中的语义化版本范围,完全按照 package-lock.json 中描述的精确版本和依赖结构去安装依赖。这是保证一致性的关键!npm install <package>@<version>
手动安装指定版本依赖时,会自动更新 package-lock.json 来反映这个新确切的依赖树状态。这通常也会更新 package.json 中该依赖的版本范围。npm update
会根据 package.json 中定义的语义化版本范围,查找并安装满足范围的最新版本(可能是次要版本或补丁版本),并自动更新 package-lock.json 到新的精确状态。
当 package-lock.json 不存在时:
npm install
会根据 package.json 中的依赖声明,解析出最新的、符合语义化版本范围的依赖树来安装。安装完成后,npm 会自动生成一个新的 package-lock.json 文件,记录下这次安装的精确快照。此时安装的结果可能会在不同时间或不同环境中因新版本的发布而略有差异。
dependencies 生产依赖
dependencies 描述项目在生产环境运行所必需的依赖包
核心依赖通过 dependencies 描述,例如:
框架/库:react, vue, express, lodash
UI 组件:antd, material-ui
工具库:axios, moment
devDependencies 开发依赖
devDependencies 描述仅在开发、测试和构建过程中需要的依赖包
生产环境部署时自动排除(通过 NODE_ENV=production)
常用于安装一些本地构建、调试、测试框架,例如:
构建工具:webpack, vite, babel
测试框架:jest, mocha, cypress
代码质量:eslint, prettier
类型检查:typescript, @types/* (TS 类型定义)
安装
npm install <package-name> --save-dev
# 或简写
npm i <package-name> -D
SemVer 语义化版本控制
npm 使用 语义化版本 SemVer 描述版本号主版本号.次版本号.修订号
MAJOR.MINOR.PATCH
在 package.json 中,dependencies 和 devDependencies 都是标准的 JSON 对象,格式相同。
dependencies 是一个对象,配置模块依赖的模块列表,key是模块名称,value是版本范围,版本范围是一个字符,可以被一个或多个空格分割。
{
"dependencies": {
"包名": "版本描述符",
// 更多生产依赖...
},
"devDependencies": {
"包名": "版本描述符",
// 更多开发依赖...
}
}
语义化版本控制 SemVer4.18.2
精确版本,拒绝任何其他版本^4.18.2
兼容版本,最常用,默认行为,允许次版本和补丁更新,允许的版本范围是 大于等于 4.18.2 且 小于 5.0.0,拒绝 5.0.0~4.18.2
安全版本,约等于,仅允许补丁更新,允许的版本号范围是 大于等于 4.18.2 且 小于 4.19.0,拒绝 4.19.04.18.x
通配符,匹配特定版本段的任何补丁更新,等效于 ~4.18.0>4.17.0 <4.19.0
区间描述符,指定版本安装范围,安装符合范围的最高版本,例如 >version
>=version
<version
4.18.2-beta.3
预发布版本,安装特定预发布版本,需明确指定完整版本号*
或 ""
任意版本,安装最新版本(高危操作),可能引入破坏性更新"latest"
安装最新正式版,等效于 *
特殊依赖
dependencies 也可以被指定为一个 git 地址或者一个压缩包地址。
1、Git 仓库依赖:
{
"dependencies": {
"private-pkg1": "git+https://github.com/user/repo.git", // 指定git仓库
"pkg-on-branch": "github:user/repo#branch-name", // 指定特定分支
"pkg-on-commit": "git+https://github.com/user/repo#commit-hash" // 指定特定提交
}
}
2、本地文件/压缩包依赖
{
"devDependencies": {
"local-pkg": "file:./path/to/local-module",
"tarball": "https://registry.com/pkg-1.2.3.tgz"
}
}
scripts 自定义脚本字段
npm run
是一个在项目中执行自定义脚本的接口,其能力来源于 package.json 文件中的 scripts
字段。
scripts
字段是 npm run 的 『指令集』scripts
字段是一个 JSON 对象,属性名(键)是自定义的脚本名称(如 dev, serve, build, lint),属性值(值)是该脚本实际要执行的 shell 命令。
例如 Vue3 项目 package.json 文件中的 scripts
字段如下:
{
"name": "my-vue3-app",
"version": "0.1.0",
"scripts": {
"dev": "vite", // 用于启动开发服务器
"build": "vite build", // 用于构建生产包
"preview": "vite preview" // 用于预览生产包
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "eslint . --fix",
"format": "prettier --write src/"
},
"dependencies": { ... },
"devDependencies": { ... }
}
npm run script-name 执行过程
在项目根目录(即包含 package.json 的目录)下运行 npm run script-name
例如 npm run dev
时,内部的执行顺序是:
1、查找 package.json: npm 首先在当前目录及其父目录中查找 package.json 文件。
2、定位 scripts
: 找到 package.json 后,npm 会查找其中的 scripts
对象。
3、匹配脚本名:npm 检查 scripts
对象中是否存在一个键(属性名)与你输入的 script-name
(例如 dev)匹配。
4、执行命令字符串:如果找到了匹配的脚本,npm 会将其值(例如 vite
)作为一个 shell 命令 在一个子进程中执行。
执行脚本命令时有个关键点:环境变量 PATH 的修改: npm 在执行这个命令前,会做一件非常重要的事情:它会将项目本地的 node_modules/.bin 目录 临时地添加到 shell 的 PATH 环境变量的最前面。
5、vite 可执行文件是一个 Node.js 脚本。它被执行后,读取项目的配置文件(如 vite.config.js),然后启动开发服务器(包含模块热重载 - HMR)、编译 Vue 单文件组件(.vue)等,最终让你的 Vue3 应用在浏览器中运行起来。
npm 常用软件
npm-pack-all 打离线安装包
npm-pack-all 是一个用于将 Node.js 项目的依赖项打包成 .tgz 文件的工具,其核心功能是将项目中的生产依赖(dependencies)和开发依赖(devDependencies)递归打包,便于离线分发或部署。
使用场景
- 离线环境部署:在无网络连接的环境中,通过 .tgz 文件安装依赖(npm install artifact.tgz)。
- 私有库/组件分发:将团队内部私有库打包后分发给成员,确保版本一致性。
npm-pack-all 与 npm pack 的区别:
npm pack
仅打包当前目录的模块(如项目自身代码),不处理依赖项。npm-pack-all
递归打包所有依赖项,生成包含完整依赖树的 .tgz 文件。
npm-check-updates
npm-check-updates
https://www.npmjs.com/package/npm-check-updates
npm-check-updates(NCU) 更新 package.json 中的依赖到最新版本,忽略指定的版本号。
安装npm-check-updates
npm install -g npm-check-updates
ncu 检测版本更新
进入 package.json 所在目录,执行 ncu
检查 package.json 中依赖的可用版本更新
这里以 hexo 为例:
# ncu
Checking /home/centos/git/hexo/package.json
[====================] 12/12 100%
hexo ^3.9.0 → ^5.4.0
hexo-deployer-git ^0.1.0 → ^3.0.0
hexo-generator-archive ^0.1.4 → ^1.0.0
hexo-generator-category ^0.1.3 → ^1.0.0
hexo-generator-index ^0.2.0 → ^2.0.0
hexo-generator-tag ^0.2.0 → ^1.0.0
hexo-renderer-ejs ^0.2.0 → ^1.0.0
hexo-renderer-marked ^1.0.1 → ^4.0.0
hexo-renderer-stylus ^0.3.1 → ^2.0.1
hexo-server ^0.2.0 → ^2.0.0
hexo-tag-bootstrap 0.0.8 → 0.2.1
hexo-wordcount ^2.0.1 → ^6.0.1
Run ncu -u to upgrade package.json
ncu -u 更新package.json
进入 package.json 所在目录,执行 ncu -u
可以更新 package.json 中的依赖版本到最新。
之后再执行 npm install
根据 package.json 中的版本号更新依赖包。
注意:ncu -u
只是更新 package.json 文件中的版本号,并不是真的安装依赖包的新版本,之后还需执行 npm install
来安装更新。
ncu -g 检查全局包更新
serve
serve 是一个非常流行的 npm 包,它提供了一个极简、零配置的静态文件服务器,专门用于在本地开发和测试环境(甚至简单的演示环境)中快速地托管静态网站(HTML, CSS, JS, 图片等)或单页应用程序(SPA)。
核心目的: 取代配置复杂的 Web 服务器(如 Apache 或 Nginx 进行本地开发设置),让你一键启动一个本地服务器来预览你的静态文件或构建产物。
通常全局安装,方便在任意目录使用:
npm install -g serve
常用参数:-s, --single
将所有不存在的 URL 重写为指定的文件(默认是 /index.html)-p, --port, -l, --listen
指定端口
serve
启动服务器(托管当前目录),默认端口是 3000(如果 3000 被占用会自动尝试其他端口)。访问 http://localhost:3000 即可
serve ./dist
指定目录启动serve -l 8080
指定端口启动
问题
npm does not support Node.js v8.17.0
npm WARN npm npm does not support Node.js v8.17.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm You can find the latest version at https://nodejs.org/
查看 node 和 npm 版本号
# node -v
v12.14.0
# npm -v
6.13.4
原因:
node 版本太新,npm版本太旧,不支持新版node
解决:
更新 npm 版本
切换到 root 用户:
# npm install -g npm
# npm -v
7.20.0
上一篇 Java-RMI
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: