第 14 章 · 包管理器对照
一句话:npm、pnpm、pip、uv、dotnet、go 这几个包管理器把清单文件里写的依赖解析成确切版本、下载到本地,同一件事在四种生态里的命令对照着查。 用它还是用别的:Node 项目看仓库里有哪个锁文件,
package-lock.json用 npm,pnpm-lock.yaml用 pnpm;Python 新项目用 uv,只有requirements.txt的老项目在虚拟环境里用 pip;.NET 用dotnet自带的 NuGet 命令,Go 用go自带的模块命令,不另装工具。 核对版本:npm 10.9(Node 22)、pnpm 12、pip 26.1、uv 0.12、.NET SDK 10.0、Go 1.27,2026-10
14.1 安装与版本
Section titled “14.1 安装与版本”多数包管理器跟着语言运行时一起装好,语言本身的安装命令见第 3 章 3.1。
| 工具 | 跟着谁来 | 查版本 |
|---|---|---|
| npm | 随 Node.js | npm --version |
| pnpm | 单独装,命令见下 | pnpm --version |
| pip | 随 Python | python -m pip --version |
| uv | 单独装,命令见下 | uv --version |
| dotnet | 随 .NET SDK | dotnet --version |
| go | 随 Go | go version |
uv 是一个独立的可执行文件,不依赖已装的 Python:
winget install --id astral-sh.uv -ebrew install uv # macOScurl -LsSf https://astral.sh/uv/install.sh | sh # Linuxpnpm 按官方文档用 npm 安装为独立程序,需 Node 22.13 以上,三个平台相同;以后升级用 pnpm self-update:
npx get-pnpm14.2 五分钟概念
Section titled “14.2 五分钟概念”- 清单文件(Manifest):手写的依赖列表,写的是版本范围,如
package.json、pyproject.toml、*.csproj、go.mod。要提交进仓库。 - 锁文件(Lockfile):工具解析版本范围后,把每个包(包括依赖的依赖)的确切版本和校验和记下来,如
package-lock.json、uv.lock。要提交,否则两台机器装出来的版本可能不同。NuGet 默认不生成,要在项目里开启(见 14.5)。Go 的go.mod本身就写最低确切版本,go.sum只存校验和。 - 版本范围:npm 的
^1.2.3允许升到2.0.0以下,~1.2.3只允许1.2.x;Python 的==2.31.0锁死,>=2.31不封顶,uv add默认写>=;NuGet 的Version="13.0.1"表示最低 13.0.1;Go 取所有依赖要求里最低能满足的版本。 - 开发依赖:只在开发和测试时用的包,如 TypeScript、pytest。npm 记在
devDependencies,生产安装npm ci --omit=dev跳过它们;uv 记在[dependency-groups]的dev组。.NET 没有单独的开发依赖命令,只在构建时用的包(如分析器)加PrivateAssets="all",测试包装在测试项目里;Go 的工具依赖用tool指令记录。 - 全局与项目本地:依赖装在项目里(
node_modules/、.venv/),互不干扰。全局装的是命令行工具,命令放在一个单独的目录里,这个目录要在 PATH 上,见 14.6。 - 镜像源(Registry):存放包的服务器,默认是 npmjs.org、PyPI、nuget.org、proxy.golang.org。国内访问慢时换成国内镜像源,包内容相同。
下图上半是四种生态共同的流程,下面四行是各自的文件名:
14.3 常用命令
Section titled “14.3 常用命令”表中包名都是示例。uv 的命令要在有 pyproject.toml 的目录里运行,dotnet 的在 *.csproj 所在目录。
| 任务 | npm | uv | dotnet | go |
|---|---|---|---|---|
| 初始化项目 | npm init -y |
uv init |
dotnet new console |
go mod init example.com/app |
| 加依赖 | npm install lodash |
uv add requests |
dotnet add package Newtonsoft.Json |
go get github.com/google/uuid |
| 加指定版本 | npm install lodash@4.17.21 |
uv add "requests==2.31.0" |
dotnet add package Newtonsoft.Json --version 13.0.1 |
go get github.com/google/uuid@v1.5.0 |
| 加开发依赖 | npm install -D typescript |
uv add --dev pytest |
无,测试包装在测试项目里 | go get -tool golang.org/x/tools/cmd/stringer |
| 删依赖 | npm uninstall lodash |
uv remove requests |
dotnet remove package Newtonsoft.Json |
go get github.com/google/uuid@none |
| 按锁文件装,不改锁文件 | npm ci |
uv sync --locked |
dotnet restore --locked-mode |
go mod download |
| 改了清单后更新锁文件 | npm install |
uv lock |
dotnet restore;--force-evaluate 全部重新解析 |
go mod tidy |
| 升级到范围内最新 | npm update |
uv lock --upgrade 再 uv sync |
dotnet package update |
go get -u ./... |
| 列出可升级的包 | npm outdated |
uv tree --outdated --depth 1 |
dotnet package list --outdated |
go list -m -u all |
| 列出已装的包 | npm ls --depth=0 |
uv tree --depth 1 |
dotnet package list |
go list -m all |
| 运行 | npm run <脚本名> |
uv run pytest |
dotnet run |
go run . |
| 清缓存 | npm cache clean --force |
uv cache clean |
dotnet nuget locals all --clear |
go clean -modcache |
| 换镜像源 | npm install --registry=<url> |
uv sync --default-index <url> |
dotnet restore --source <url> |
go env -w GOPROXY=<url>,direct |
最后一行前三格只对这一条命令生效,Go 那一格写进用户配置、长期生效;长期配置见 14.4。
pnpm 的写法和 npm 基本一样,不同的是:加依赖 pnpm add(开发依赖 pnpm add -D),删依赖 pnpm remove,按锁文件装 pnpm install --frozen-lockfile(CI 环境里默认就是),清缓存 pnpm store prune。pip 的锁文件(pip lock,pylock.toml)还是实验功能,常用 pip freeze > requirements.txt 记下确切版本,pip install -r requirements.txt 照着装;其余在虚拟环境里用 pip install requests、pip uninstall requests、pip install -U requests、pip list --outdated、pip cache purge,换源加 -i <url>。
14.4 典型工作流
Section titled “14.4 典型工作流”拿到别人的项目,先按锁文件装
Section titled “拿到别人的项目,先按锁文件装”只装锁文件里的版本,锁文件和清单对不上就报错,不会悄悄改锁文件。CI 里用 npm ci,见第 10 章。
- 克隆并进入项目:
git clone <url>。 - Node 项目,按
package-lock.json装,已有的node_modules/会先被整个删掉:npm ci。 - Python 项目,自动建
.venv并按uv.lock装:uv sync --locked。 - 只有
requirements.txt的 Python 项目,先建并激活虚拟环境(第 3 章 3.4),再装:python -m pip install -r requirements.txt。 - .NET 项目,有
packages.lock.json时:dotnet restore --locked-mode。 - Go 项目,下载
go.mod列的模块并核对go.sum:go mod download。 - 跑一下测试确认环境齐了:
npm test、uv run pytest、dotnet test或go test ./...。
配好国内镜像源
Section titled “配好国内镜像源”下面的地址是常用的例子,除第 3 步外都写进用户级配置,对所有项目生效;只想对一个项目生效,写进项目里的配置文件(见 14.5)。
- npm(pnpm 也读这个设置):
npm config set registry https://registry.npmmirror.com/。 - pip:
python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple。 - uv 不读 pip 的配置,把 14.5 的最小
uv.toml放到用户级位置;只对这一次生效时加参数:uv sync --default-index https://mirrors.aliyun.com/pypi/simple/。 - NuGet 加华为云镜像源:
dotnet nuget add source https://mirrors.huaweicloud.com/repository/nuget/v3/index.json -n huawei。 - 停用 nuget.org,否则它连不上时还原照样报错:
dotnet nuget disable source nuget.org。 - Go:
go env -w GOPROXY=https://goproxy.cn,direct。 - 核对生效:
npm config get registry、python -m pip config list、dotnet nuget list source、go env GOPROXY。
同一台机器上用多个运行时版本
Section titled “同一台机器上用多个运行时版本”- Node 用 fnm(Windows 也可用 nvm-windows),先装 fnm:
winget install Schniz.fnm。 - 按 fnm 文档把
fnm env --use-on-cd加进 shell 配置文件后,装并切换 Node 版本:fnm install 22再fnm use 22。 - Python 不用另装管理器,uv 自己下载解释器:
uv python install 3.14。 - 让本项目固定用这个版本,写进
.python-version:uv python pin 3.14。 - .NET 多个 SDK 可以并存,在项目根目录写
global.json指定用哪个:dotnet new globaljson --sdk-version 10.0.401 --roll-forward latestFeature。 - 核对当前目录用的 SDK:
dotnet --version。 - Go 在
go.mod写了更高的go版本时,go命令会自动下载对应工具链;要并存一个旧版本:go install golang.org/dl/go1.26.0@latest,再运行go1.26.0 download。
14.5 配置要点
Section titled “14.5 配置要点”项目级配置放在项目根目录,随仓库提交,优先于用户级。
| 配置项 | 项目级 | 用户级 Windows | 用户级 macOS / Linux |
|---|---|---|---|
| npm、pnpm | .npmrc |
%USERPROFILE%\.npmrc |
~/.npmrc |
| pip | 虚拟环境目录里的 pip.ini(Linux/macOS 为 pip.conf) |
%APPDATA%\pip\pip.ini |
~/.config/pip/pip.conf |
| uv | uv.toml 或 pyproject.toml 的 [tool.uv] |
%APPDATA%\uv\uv.toml |
~/.config/uv/uv.toml |
| NuGet | nuget.config |
%APPDATA%\NuGet\NuGet.Config |
~/.nuget/NuGet/NuGet.Config |
| Go | 无,用环境变量 | go env -w 写入 %APPDATA%\go\env |
~/.config/go/env(macOS 为 ~/Library/Application Support/go/env) |
| NuGet 锁文件开关 | *.csproj 里的 RestorePackagesWithLockFile |
— | — |
pnpm 只从 .npmrc 读镜像源和认证,下面片段的后两项只对 npm 生效。NuGet 要生成 packages.lock.json,在 *.csproj 的 <PropertyGroup> 里加一行 <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>,再 dotnet restore。
最小 .npmrc,放在项目根目录:
# 从国内镜像源下载;锁文件里会记下这个地址registry=https://registry.npmmirror.com/# npm install 写入确切版本,不加 ^save-exact=true# 当前 Node 版本不符合 package.json 的 engines 时直接报错engine-strict=true最小 uv.toml,放在 pyproject.toml 旁边:
# 默认索引换成国内镜像源,uv add、uv lock、uv sync 都从这里下载[[index]]url = "https://pypi.tuna.tsinghua.edu.cn/simple"default = true # 取代 PyPI,而不是在 PyPI 之外再加一个14.6 注意事项
Section titled “14.6 注意事项”npm ci报EUSAGE,说package.json and package-lock.json ... are in sync。 原因:改了package.json,锁文件没跟着更新。处理:本机npm install后提交锁文件;uv 报but --locked was provided时运行uv lock。- 全局装的命令报
The term 'tsc' is not recognized或command not found。 原因:全局工具目录不在 PATH 上。处理:用npm prefix -g、uv tool dir --bin、go env GOPATH(其下bin)查目录,dotnet 是~/.dotnet/tools,加进 PATH 后重开终端。 - Linux 上
pip install报error: externally-managed-environment;Windows 上包装进了系统 Python,别的项目跟着变。 原因:没进虚拟环境,pip 装到了系统 Python。处理:先python -m venv .venv并激活再装,或改用uv add,uv 自动用项目的.venv。 - 装包卡住或超时:
ETIMEDOUT、ReadTimeoutError、NU1301、i/o timeout。 原因:默认镜像源在国外,访问慢或连不上。处理:按 14.4 配国内镜像源,npm config get registry或go env GOPROXY核对确实生效。 - 合并分支后锁文件里出现
<<<<<<<冲突标记。 原因:两边都改了依赖,锁文件是生成的,手改容易漏掉依赖的依赖。处理:先解决清单文件的冲突,再取一边的锁文件重新生成:git checkout --theirs package-lock.json后npm install(uv 用uv lock,Go 用go mod tidy)。
14.7 深入阅读
Section titled “14.7 深入阅读”- npm 命令参考:npm install、ci、update、config 等每个命令的参数,.npmrc 的全部配置项也在这里。
- uv 文档:项目、依赖、锁文件、Python 版本管理和 uv.toml 的写法,先看 Projects 一节。
- pip 用户指南:requirements 文件、配置文件位置、换索引和缓存。
- NuGet 文档:dotnet 的包引用、nuget.config、锁文件和包源的配置。
- Go Modules 参考:go.mod、go.sum、最小版本选择、GOPROXY 和 go get 的完整说明。