什么是npm_如何在javascript项目中管理依赖包【教程】

npm是JavaScript项目无法绕开的依赖管理工具,兼具包仓库、命令行客户端和本地依赖记录功能;其安装行为由-g参数和package.json存在与否决定,依赖分类影响生产环境体积与运行时可用性,嵌套结构源于版本冲突,需通过升级npm或改用pnpm优化,且

package-lock.json是依赖可重现性的唯一凭证。

npm 不是“要不要用”的问题,而是 JavaScript 项目里你几乎没法绕开的依赖管理工具——它既是包仓库,也是命令行客户端,还是项目本地依赖关系的记录者。

npm install 为什么有时装全局,有时装本地?

关键看有没有 -g 参数,以及当前目录下是否存在 package.json

  • 运行 npm install lodash:默认安装到当前项目 node_modules 目录,同时写入 package.jsondependencies
  • 运行 npm install -g eslint:装进系统级 node_modules(如 /usr/local/lib/node_modules),所有项目都能调用 eslint 命令,但不会影响当前项目的依赖树
  • 没有 package.json 时执行 npm install,会报错 ERR! code ENOENT —— npm 需要这个文件来锁定依赖版本和结构

package.json 中 dependencies 和 devDependencies 有什么实际区别?

区别不在安装行为,而在语义、打包逻辑和 CI/CD 流程中是否被忽略:

  • dependencies:运行时必需的包,比如 reactaxios。执行 npm install --production 时只装它们
  • devDependencies:仅开发阶段需要,比如 webpackjest。部署时通常跳过,能减小生产环境体积
  • 误把 lodash 放进 devDependencies,上线后代码调用 _.debounce 就会直接报 ReferenceError: _ is not defined

为什么 npm install 后 node_modules 里有成百上千个子文件夹?

这是 npm v6 及之前默认的嵌套结构,源于“扁平化失败”——当不同依赖要求同一包的不同版本时,npm 会在各自父级下重复安装:

node_modules/
├── axios@1.6.0
│   └── node_modules/
│       └── follow-redirects@1.15.2  ← axios 自己的依赖
├── request@2.88.2
│   └── node_modules/
│       └── follow-redirects@1.14.7  ← 版本不兼容,无法提升复用

这会导致磁盘占用大、启动慢、甚至因路径过长在 Windows 上报错。解决方案是:

  • 升级到 npm v7+(默认启用 dedupe 和更激进的扁平化)
  • 或手动运行 npm dedupe(v6 可用)
  • 更彻底的方式:改用 pnpm,用硬链接 + 符号链接避免重复拷贝

npm ci 和 npm install 不能混用

npm ci 是为自动化环境(CI/CD)设计的,它完全忽略 package-lock.json 以外的任何输入

  • 必须存在 package-lock.json,否则直接退出
  • 不会修改 package-lock.json,也不会写入 package.json
  • 删除整个 node_modules 后重装,确保所有人、所有机器得到一模一样的依赖树
  • 如果本地开发用 npm install 升级了某个包但没提交 package-lock.json,CI 上跑 npm ci 就会装旧版,导致“本地能跑,线上报错”

真正容易被忽略的是:package-lock.json 不是“可选配置”,它是依赖可重现性的唯一凭证;删掉它再 npm install,哪怕 package.json 没变,也可能装上新版间接依赖,引发静默不兼容。