包的安装

设置淘宝镜像

  1. 由于 npm 的官方 registry 服务器位于国外,可能受网速影响导致下载缓慢或失败;因此,安装好 npm 之后,需要重新设置 registry 的地址为国内地址;

  2. 目前,淘宝提供了国内的 registry 地址,先设置到该地址,设置方式为 npm config set registry https://registry.npm.taobao.org

  3. 设置好后,通过命令 npm config get registry 进行检查;

本地安装

  1. 使用命令 npm install 包名npm i 包名 即可完成本地安装;

  2. 本地安装的包出现在当前目录下的 node_modules 目录中;

    1. 随着开发的进展,node_modules 目录会变得异常庞大,目录下的内容不适合直接传输到生产环境,因此通常使用 .gitignore 文件忽略该目录中的内容;
    2. 本地安装适用于绝大部分的包,它会在当前目录及其子目录中发挥作用,通常在项目的根目录中使用本地安装;
    3. 安装一个包的时候,npm 会自动管理依赖,它会下载该包的依赖包到 node_modules 目录中;
    4. 如果本地安装的包带有 CLInpm 会将它的 CLI 脚本文件放置到 node_modules/.bin 下,使用命令 npx 命令名 即可调用;

全局安装

  1. 使用命令 npm install --global 包名npm i -g 包名 即可完成全局安装;

  2. 全局安装的包放置在一个特殊的全局目录,该目录可以通过命令 npm config get prefix 查看,大部分情况下,都不需要全局安装包,除非:

    1. 包的版本非常稳定,很少有大的更新;
    2. 提供的 CLI 工具在各个工程中使用的非常频繁;
    3. CLI 工具仅为开发环境提供支持,而非部署环境;

包的配置

目前遇到的问题:

  1. 拷贝工程后如何还原?
  2. 如何区分开发依赖和生产依赖?
  3. 如果自身的项目也是一个包,如何描述包的信息?

以上这些问题都需要通过包的 配置文件 解决;

配置文件 package.json

  1. 可以手动创建该文件,而更多的时候,是通过命令 npm init 创建的,配置文件中可以描述大量的信息,包括:

    {
      // 核心元信息
      "name": "my-vue3-admin",        // 项目名称:小写、无空格,发布npm包时必填
      "version": "1.0.0",             // 版本号:遵循语义化版本(主版本.次版本.修订号)
      "description": "Vue3 + Vite 后台管理系统", // 项目描述:说明项目用途,npm搜索时展示
      "main": "dist/index.js",        // 入口文件:Node.js环境下require导入时加载的文件(前端项目若不需要 Node.js 环境可删除)
      "type": "module",               // 模块类型:module=ES模块(支持import/export),commonjs=传统模块(默认)
      
      // 自定义脚本命令:通过npm run <命令名>执行
      "scripts": {
        "dev": "vite",                // 启动开发环境
        "build": "vite build",        // 打包生产环境代码
        "preview": "vite preview",    // 预览打包后的项目
        "lint": "eslint . --ext .vue,.js,.ts", // 代码格式检查
        "test": "vitest"              // 执行单元测试
      },
    
      // 生产环境依赖:项目运行时必须的包(如框架、请求库)
      "dependencies": {
        "vue": "^3.4.15",             // ^表示兼容次版本更新(3.4.x)
        "vue-router": "^4.2.5",       // Vue路由库
        "pinia": "^2.1.7",            // Vue状态管理库
        "axios": "^1.6.5"             // HTTP请求库
      },
    
      // 开发环境依赖:仅开发/构建时需要(如构建工具、代码检查工具)
      "devDependencies": {
        "@vitejs/plugin-vue": "^5.0.3", // Vite的Vue插件
        "vite": "^5.0.10",            // 前端构建工具
        "eslint": "^8.56.0",          // 代码检查工具
        "eslint-plugin-vue": "^9.19.2", // Vue专属ESLint规则
        "vitest": "^1.1.0"            // 单元测试框架
      },
    
      // 项目作者信息:格式为 姓名 <邮箱> (网址)
      "author": "小明 <xiaoming@example.com>",
      "license": "MIT",               // 开源许可证:规定项目的使用权限
      "keywords": ["vue3", "admin", "vite", "pinia"], // 关键词:npm搜索时匹配
    
      // 环境限制:指定项目运行的Node.js版本范围
      "engines": {
        "node": ">=18.0.0",
        "npm": ">=8.0.0"
      },
    
      // 工具配置:直接在package.json中配置ESLint,替代单独的.eslintrc文件
      "eslintConfig": {
        "root": true,                 // 标记当前目录为ESLint配置根目录
        "env": {                      // 环境配置:启用node和浏览器全局变量
          "node": true,
          "browser": true
        },
        "extends": [                  // 继承的规则集
          "plugin:vue/vue3-recommended", // Vue3推荐规则
          "eslint:recommended"        // ESLint官方推荐规则
        ]
      },
    
      // 若不需要发布到 npm 仓库,repository、bugs、homepage 等字段可以省略
      // 代码仓库地址:说明源码存放位置
      "repository": {
        "type": "git",
        "url": "git+https://github.com/xxx/my-vue3-admin.git"
      },
    
      // 问题反馈地址:指定GitHub Issues地址
      "bugs": {
        "url": "https://github.com/xxx/my-vue3-admin/issues"
      },
    
      // 项目主页:文档或演示地址
      "homepage": "https://github.com/xxx/my-vue3-admin#readme"
    }
    
  2. 使用 npm init --yesnpm init -y 可以在生成配置文件时自动填充默认配置;

保存依赖关系

  1. package.json 文件最重要的作用,是记录当前工程的依赖;

    1. dependencies:生产环境的依赖包;
    2. devDependencies:仅开发环境的依赖包;
  2. 配置好依赖后,使用下面的命令即可安装依赖:

    ## 本地安装所有依赖 dependencies + devDependencies
    npm install
    npm i
    
    ## 仅安装生产环境的依赖
    npm install --dependencies
    
    ## 仅安装开发环境的依赖
    npm install --production
    
  3. 这样一来,代码移植就不是问题了,只需要移植源代码和 package.json 文件,不用移植 node_modules 目录,然后在移植之后通过命令即可重新恢复安装;

    ## 安装依赖到生产环境
    npm i 包名
    npm i --save 包名
    npm i -S 包名
    
    ## 安装依赖到开发环境
    npm i --save-dev 包名
    npm i -D 包名
    

包的使用

nodejs 对 npm 支持非常良好

  1. 当使用 nodejs 导入模块时,如果模块路径不是以 ./…/ 开头,则 node 会认为导入的模块来自于 node_modules 目录,例如:

    var _ = require("lodash");
    
  2. 它首先会从当前目录的以下位置寻找文件:

    node_modules/lodash.js
    node_modules/lodash/入口文件
    
  3. 若当前目录没有这样的文件,则会回溯到上级目录按照同样的方式查找;

  4. 如果到顶级目录都无法找到文件,则抛出错误;

入口文件规则

  1. 查看导入包的 package.json 文件,读取 main 字段作为入口文件,若不包含 main 字段,则使用 index.js 作为入口文件;

  2. 入口文件的规则同样适用于自己工程中的模块,在 node 中,还可以手动指定路径来导入相应的文件,这种情况比较少见;

npm 缓存相关命令

# 清除缓存
npm cache clean -f

# 获取缓存位置
npm config get cache

# 设置缓存位置
npm config set cache "新的缓存路径"

语义版本

如果你编写了一个包 A ,依赖另外一个包 B ,你在编写代码时,包 B 的版本是 2.4.1 ,你是希望使用你包的人一定要安装包 B ,并且是 2.4.1 版本,还是希望他可以安装更高的版本,如果你希望它安装更高的版本,高的什么程度呢?

版本号规则

  1. 版本规范:主版本号.次版本号.补丁版本号

    部分 命名 变更场景 (核心规则) 示例 (从 1.2.3 变更)
    第一部分 主版本号 (MAJOR) 包含不兼容的 API 变更 (破环性更新) 2.2.3 (API 重构)
    第二部分 次版本号 (MINOR) 新增兼容的功能 (功能性更新,不影响旧代码) 1.3.3 (新增一个接口)
    第三部分 修订号 (PATCH) 仅修复兼容的 bug (无新功能,无 API 变更) 1.2.4 (修复一个已知 bug)
  2. 语义版本的书写规则非常丰富,下面列出了一些常见的书写方式 (以基准版本 1.2.3 为例)

    符号 / 格式 名称 / 含义 示例 允许的版本范围 风险等级
    ^ 兼容版本:允许次版本、修订号更新 (主版本不变) ^1.2.3 1.2.3 → 1.x.x
    ~ 补丁版本:仅允许修订号更新 (主 / 次版本不变) ~1.2.3 1.2.3 → 1.2.x
    无符号 精确版本:只能安装指定版本,无任何更新 1.2.3 仅 1.2.3
    > 大于指定版本 >1.2.3 所有版本号高于 1.2.3
    < 小于指定版本 <1.2.3 所有版本号低于 1.2.3
    >= 大于等于指定版本 >=1.2.3 1.2.3 及所有更高版本 中高
    <= 小于等于指定版本 <=1.2.3 1.2.3 及所有更低版本 中高
    - 版本区间:等同于 >=左版本 <=右版本 1.2.3 - 2.4.5 1.2.3 到 2.4.5 之间的所有版本
    * 任意版本:匹配所有版本 * / 1.* / 1.2.* *= 所有版本 极高
    x 通配符:与 * 作用完全一致 (别名) * / 1.* / 1.2.* *= 所有版本 极高

差异版本处理 package-lock.json

  1. lock 文件锁定精确版本 (最推荐),这是解决「不同环境版本不一致」的核心方案,也是 npm 官方推荐的最佳实践;

    1. 原理:package-lock.json (npm) / yarn.lock (yarn) 会记录每一个依赖 (包括嵌套依赖) 的精确版本、下载地址、哈希值,后续安装时会忽略 package.json 的版本范围,直接安装 lock 文件里的精确版本;
    2. 实操步骤:
      • 初始化 / 安装依赖后,npm 会自动生成 package-lock.json
      • package-lock.json 提交到代码仓库 (不要加入 .gitignore)
      • 其他开发者 / 部署环境执行 npm install 时,会严格按照 lock 文件安装版本,保证环境一致;
    3. 注意:
      • 手动修改 package.json 的版本范围后,执行 npm install 不会更新 lock 文件,需执行 npm update <包名> 或删除 lock 文件重新安装;
      • lock 文件仅锁定版本,不会阻止手动执行 npm install <包名>@新版本
  2. 精确声明版本 (无符号):如果不想依赖 lock 文件,可直接在 package.json 中写无符号的精确版本,强制 npm 安装指定版本;

  3. 处理嵌套依赖的版本冲突:

    1. npm 自动处理逻辑:
      1. 若两个版本范围兼容 (如项目依赖 ^2.0.0,嵌套依赖 ^2.1.0)npm 会提升到同一个版本,只安装一份;
      2. 若版本不兼容 (如项目依赖 2.x,嵌套依赖 3.x)npm 会在嵌套依赖的 node_modules 下单独安装一份,避免冲突;
    2. 手动强制统一版本:使用 npm overrides (npm 8.3+ 支持)package.json 中强制指定嵌套依赖的版本:
      {
        "dependencies": {
          "A": "1.0.0" // A 依赖 B@2.0.0
        },
        "overrides": {
          "B": "3.0.0" // 强制所有地方的 B 都用 3.0.0
        }
      }
      
  4. 检查并更新差异版本,当发现本地 node_modules 版本与 package.json 声明不一致时,可通过以下命令排查 / 修复:

    命令 作用 适用场景
    npm ls <包名> 查看指定包的实际安装版本、依赖树 排查「声明版本 vs 实际版本」差异
    npm outdated 列出所有超出 package.json 范围的依赖 查看哪些依赖有可更新的版本
    npm update <包名> package.json 版本范围更新到最新版 主动升级到范围內的最新版本
    npm install <包名>@指定版本 强制安装指定版本 (会更新 package.json) 手动修正版本差异
    npm ci 严格按 lock 文件安装 (删除现有 node_modules) 部署环境 / CI 确保版本完全一致

npm 脚本

npm 脚本 (package.json 中的 scripts 字段)Node.js / 前端项目的核心工具,本质是命令行指令的别名,能把复杂的终端命令封装成简单的 npm run <指令> 形式,还支持跨平台兼容、钩子函数、环境变量等高级特性;

基础用法

  1. 基本结构:在 package.jsonscripts 字段中,键是「脚本别名」,值是「要执行的终端命令」:

    1. 执行方式:npm run <别名> (核心命令),如 npm run dev
    2. 简写规则:部分常用脚本可省略 run,如 npm start (对应 “start”)npm test (对应 “test”)npm stop (对应 “stop”)
    {
      "scripts": {
        "dev": "vite",          // 简写:npm run dev
        "build": "vite build",  // 简写:npm run build
        "test": "jest --coverage" // 带参数的命令
      }
    }
    
  2. 脚本的执行环境:npm 执行脚本时,会自动把 node_modules/.bin 目录加入系统的 PATH 环境变量,这意味着:

    1. 无需全局安装依赖 (如 vite、eslint),只要本地 devDependencies 安装了,就能直接在脚本中使用命令;
    2. 无需写完整路径 (如 ./node_modules/.bin/vite),直接写 vite 即可;
    {
      "scripts": {
        "lint": "eslint src/**/*.js" // 直接用 eslint 命令,无需全局安装
      }
    }
    

核心特性

  1. 脚本串联执行:

    符号 含义 示例 说明
    && 串行执行 (前一个成功,才执行后一个) “build:all”: “npm run build:css && npm run build:js” 先编译 CSS,再编译 JS
    & 并行执行 (同时执行,跨平台兼容性差) “dev:all”: “npm run dev:server & npm run dev:client” 同时启动服务端和客户端
  2. 钩子脚本 (生命周期)

    1. npm 提供了「前置钩子」和「后置钩子」,会在执行指定脚本时自动触发,格式为 pre<脚本名> / post<脚本名>
      {
        "scripts": {
          "prebuild": "rimraf dist", // 执行 build 前自动运行:清空 dist 目录
          "build": "vite build",
          "postbuild": "echo '打包完成!'" // 执行 build 后自动运行:提示打包完成
        }
      }
      
    2. 执行 npm run build 时,实际执行顺序:prebuildbuildpostbuild
  3. 环境变量:

    1. npm 内置环境变量:npm 会自动注入一些变量,常用的有:
      • npm_package_name:项目名称 (对应 package.json 的 name)
      • npm_package_version:项目版本 (对应 package.json 的 version)
      • npm_package_scripts_<脚本名>:脚本内容;
      {
        "scripts": {
          "info": "echo 项目名称:$npm_package_name,版本:$npm_package_version"
        }
      }
      
    2. 自定义环境变量:跨平台推荐用 cross-env(解决 Windows/Linux 环境变量语法差异)JavaScript 中通过 process.env.NODE_ENV 获取;
      {
        "scripts": {
          "dev:prod": "cross-env NODE_ENV=production vite", // 注入 NODE_ENV=production
          "dev:dev": "cross-env NODE_ENV=development vite"
        }
      }
      

进阶技巧

  1. 脚本复用 (变量 / 外部文件)

    1. npm run 调用其他脚本
      {
        "scripts": {
          "lint:js": "eslint src/**/*.js",
          "lint:css": "stylelint src/**/*.css",
          "lint": "npm run lint:js && npm run lint:css" // 复用已有脚本
        }
      }
      
    2. 提取公共命令到配置,复杂脚本可把公共部分提取到 config 字段:
      {
        "config": {
          "srcDir": "src",
          "distDir": "dist"
        },
        "scripts": {
          "build": "vite build --outDir $npm_package_config_distDir",
          "lint": "eslint $npm_package_config_srcDir/**/*.js"
        }
      }
      
  2. 传递参数 (-- 分隔符)

    1. npm 脚本传递参数时,需要用 分隔「npm 命令」和「脚本参数」:
      {
        "scripts": {
          "test": "jest"
        }
      }
      
    2. 执行:npm run test -- --coverage → 等价于 jest --coverage
  3. 跨平台兼容:

    1. WindowsLinux/macOS 的终端命令语法差异,推荐用跨平台工具:
      场景 Linux/macOS 命令 Windows 命令 跨平台替代工具
      删除目录 rm -rf dist rd /s/q dist rimraf dist (需安装 rimraf)
      复制文件 cp copy cpy (需安装 cpy)
    2. 示例:
      {
        "scripts": {
          "clean": "rimraf dist", // 跨平台删除目录
          "prebuild": "npm run clean"
        }
      }
      

其他 npm 命令

  1. 安装命令:

    # 安装最新版本
    npm install --save-exact 包名 
    npm install -E 包名
    
    # 安装指定版本
    npm install 包名@版本号
    
  2. 查询命令:

    # -g 查询包安装全局路径
    npm root [-g]
    
    # 查看包信息,子信息是 package.json 中的字段,以下方式等价
    npm view 包名 [子信息]
    npm v 包名 [子信息]
    npm info 包名 [子信息]
    npm show 包名 [子信息]
    
    # 查看 react 包的 name、versions
    npm show react name
    npm show react versions
    
    # -g 全局
    # depth 深度从 0 开始
    npm list [-g] [--depth=依赖深度]
    npm ls [-g] [--depth=依赖深度]
    npm la [-g] [--depth=依赖深度]
    npm ll [-g] [--depth=依赖深度]
    
  3. 更新命令:

    # 检查有哪些包需要更新
    npm outdated
    
    # 更新包,以下方式等价
    npm update [-g] [包名]
    npm up [-g] [包名]
    npm upgrade [-g] [包名]
    
  4. 卸载包命令:

    # 以下方式等价
    npm uninstall [-g] 包名
    npm remove [-g] 包名
    npm rm [-g] 包名
    npm r [-g] 包名
    npm un [-g] 包名
    npm unlink [-g] 包名
    

npm 配置

  1. npm 的配置会对其他命令产生或多或少的影响,安装好 npm 之后,最终会产生两个配置文件,一个是用户配置,一个是系统配置,当两个文件的配置项有冲突的时候,用户配置会覆盖系统配置;

  2. 通常,我们不关心具体的配置文件,而只关心最终生效的配置,通过下面的命令可以查询目前生效的各种配置:

    npm config ls [-l] [--json]
    
  3. 可以通过下面的命令操作配置:

    # 获取某个配置项
    npm config get 配置项
    
    # 设置某个配置项
    npm config set 配置项=值
    
    # 移除某个配置项
    npm config delete 配置项
    

npm 发布

  1. 准备工作:

    1. 移除淘宝镜像源;
    2. npm 官网注册一个账号,并完成邮箱认证;
    3. 本地使用 npm cli 进行登录
      • 使用命令 npm login 登录;
      • 使用命令 npm whoami 查看当前登录的账号;
      • 使用命令 npm logout 注销;
    4. 创建工程根目录;
    5. 使用 npm init 进行初始化;
  2. 发布:开发 -> 确定版本 -> 使用命令 npm publish 完成发布;

  3. 开源协议:

面试题

解释一下 npm 模块安装机制是什么?

参考答案:

  1. npm 会检查本地的 node_modules 目录中是否已经安装过该模块,如果已经安装,则不再重新安装;
  2. npm 检查缓存中是否有相同的模块,如果有,直接从缓存中读取安装;
  3. 如果本地和缓存中均不存在,npm 会从 registry 指定的地址下载安装包,然后将其写入到本地的 node_modules 目录中,同时缓存起来;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 包的安装
    1. 1.1. 设置淘宝镜像
    2. 1.2. 本地安装
    3. 1.3. 全局安装
  2. 2. 包的配置
    1. 2.1. 配置文件 package.json
    2. 2.2. 保存依赖关系
  3. 3. 包的使用
    1. 3.1. nodejs 对 npm 支持非常良好
    2. 3.2. 入口文件规则
    3. 3.3. npm 缓存相关命令
  4. 4. 语义版本
    1. 4.1. 版本号规则
    2. 4.2. 差异版本处理 package-lock.json
  5. 5. npm 脚本
    1. 5.1. 基础用法
    2. 5.2. 核心特性
    3. 5.3. 进阶技巧
  6. 6. 其他 npm 命令
  7. 7. npm 配置
  8. 8. npm 发布
  9. 9. 面试题
    1. 9.1. 解释一下 npm 模块安装机制是什么?