尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用mise一站式管理Node、Python和JDK多版本

用mise一站式管理Node、Python和JDK多版本 1. 先说个真实的痛为什么我们总是在 Node、Python、JDK 之间反复横跳干过几年全栈或者偏后端的同学基本都经历过这种场景公司老项目用 Java 8 Spring Boot新项目要 Java 17前端练手仓库要求 Node 14工作项目却锁 Node 20到跑数据分析脚本时Python 又要切到 3.8。以前我全靠手动改 PATH后来慢慢升级为 nvm 管 Node、pyenv 管 PythonJDK 就装两三个放在固定目录里每次部署前手动改 JAVA_HOME。表面上看各管各的问题似乎不大但只要你像我一样同时维护四五个仓库就会发现这套“各立山头”的方案有多浪费时间。这也是我后来会想找一个工具统一管理 Node / Python / JDK 多版本的核心动机。不是 nvm 和 pyenv 不好它们在自己的单语言领域做得都不错但当你遇到“一个前端项目 一个数据分析项目 一个 Java 后端项目”并行开发时就得在三个终端里分别激活不同的版本稍不留神就会在一个仓库里跑错运行时版本。这个工具方案适合那些不想记太多命令、不想维护多个版本管理器的同学也适合需要在团队和 CI 环境里快速复现指定运行时版本的朋友。2. 为什么我最终选了 mise而不是继续堆一个“新工具”2.1 在聊 mise 之前先把 asdf 说清楚如果你在社区里搜“统一版本管理”十有八九会先看到 asdf。asdf 的思路很直接它本身不负责编译只通过插件去对接不同运行时比如 nodejs、python、java 都有官方插件。只要按照插件说明装好你就可以用同一套命令去 install、use、global 不同语言的指定版本。我在调研阶段也认真试过 asdf它的插件体系做得确实广几乎你能想到的开发工具都有插件。真正让我犹豫的是两点一是 asdf 用 shell 脚本实现命令多了以后响应会慢尤其是在 CI 容器或临时 shell 里二是 asdf 的 shims 机制偶尔会引入一些“命令被劫持”的问题排查起来会比较绕。所以当我知道了 mise 这个工具之后很快就决定把主力切到 mise 上。2.2 mise 到底香在哪Rust 重写、配置集中、和 asdf 插件兼容mise 的前身是 rtx再往前是另一个 Node 版本工具的演进等于作者已经把“管理好 Node”这件事做了很多年。后来他用 Rust 重写定位变成“dev tools manager”也就是不只管 Node还管 Python、Java、Ruby、Go甚至你可以让它管理 terraform、awscli 这类系统级命令行工具。我实际用下来最明显的感受是速度。执行mise install node20和mise use node20基本是即时响应的不像有些脚本型管理器要等一两秒才开始干活。mise 还能直接复用 asdf 的插件比如很多比较冷门的运行时只要 asdf 社区有插件mise 也能用迁移成本非常低。再加上 mise 的配置文件是 TOML 格式你可以把一个项目的所有运行时版本和少量环境变量写进同一个文件这在仓库协作时特别方便。2.3 那 nvm 和 pyenv 到底要不要彻底卸载我的建议是先保留一段时间但不要让它们和 mise 同时进入同一个 PATH。为什么因为 nvm 和 pyenv 默认会在你的 shell 配置里注入一堆函数和 shims它们会抢先拦截 node、python 这些命令。你这边费了半天劲用 mise 切到 Node 18结果node -v显示的仍然是 nvm 里某个版本这种冲突查起来特别让人头大。更稳妥的做法是先把 shell 配置里 nvm、pyenv 的初始化脚本注释掉重新开一个终端确认which node已经指向 mise 管理的路径之后再决定要不要卸载。如果你还有其它老项目依赖 nvm 的特定 alias可以先留着但日常开发尽量用 mise 走统一入口。3. 安装和初始化把统一版本管理环境从一个空终端跑起来3.1 macOS / Linux 装 mise 的两种方式macOS 上如果装了 Homebrew直接就是一行brew install mise不想走 Homebrew 的话可以用官方安装脚本curl https://mise.run | sh这个脚本会下载一个编译好的二进制放到~/.local/bin/mise并打印出接下来需要加进 shell 配置的初始化行。Linux 上也一样不管你的发行版是 Ubuntu、CentOS 还是 Debian只要网络能到 GitHub Releases基本都能装。我建议优先用官方脚本这样你拿到的总是最新版本而 Homebrew 那边的更新有时会慢半拍。有些公司的内网环境访问 GitHub 很费劲这种时候你可以先在有网的机器上下载对应架构的 tar.gz再传到内网机器上解压把mise这个二进制放到/usr/local/bin/或者~/.local/bin/。mise 本身是单文件依赖很少比装什么 nvm 再加 Node 编译链要省心得多。3.2 初始化 shell 环境让 mise 接管命令查找路径安装完以后你需要让 shell 每次启动时都加载 mise。常用的 shell 无非 bash 和 zsh对应的写法如下。zsh 用户执行echo eval $(mise activate zsh) ~/.zshrcbash 用户执行echo eval $(mise activate bash) ~/.bashrc这里的核心原理是mise activate会生成一段 shell 函数它会在你敲node、python、java这些命令时动态判断当前目录下有没有对应的版本配置有的话就自动切过去没有就走系统默认。这种“按目录自动切换”的体验和 dash 极像开一个终端进到某个项目目录node -v自动变成项目锁定的版本不需要你手动 source 任何脚本。注意一定要在执行安装脚本以后开一个新终端窗口或者在当前终端里手动 source 一次配置文件否则mise这个命令本身是找不到的。3.3 Windows 用户怎么办mise 官方对 Windows 原生环境支持得不算好最省事的路径是装一个 WSL2然后在 WSL2 里的 Linux 发行版上按照上面的步骤装。你可以在 Windows 上用 VS Code 的 Remote-WSL 打开项目目录终端里直接跑mise use node20体验和 Linux 一样顺滑。如果你不想上 WSL又必须在 Windows 自带终端里跑也可以试试 Git Bash 或者 MSYS2 环境。但据我实测PowerShell 里对 shell hook 的兼容性总会有一些边缘情况比如启动速度变慢、环境变量偶尔丢失。所以我的建议很明确Windows 下就老老实实 WSL2日常开发体验最稳也不会有“npm 命令无法加载”这类 PowerShell 执行策略的问题。4. 日常实操Node、Python、JDK 全部交给 mise 来管4.1 先记下这几个命令足够应付绝大多数场景mise 的常用命令比 nvm / pyenv / jenv 三套加起来还要少。最核心的是下面这几个命令作用mise ls-remote node列出 node 的远程可用版本mise install node20.18.1安装指定版本mise use node20.18.1在当前目录的 .mise.toml 里锁定该版本mise use -g node20.18.1设置为全局默认版本mise ls查看已安装的所有版本mise uninstall node20.18.1删除某个已装版本mise exec node20 -- node -v临时用某版本执行单条命令mise current查看当前生效的版本其中mise use是最常用的一条它会自动帮你写好.mise.toml并立刻把这个版本放到当前 shell 的 PATH 里。我建议把.mise.toml提交进 Git 仓库这样同事拉到代码后只要执行mise install就能恢复和线上环境一致的运行时。4.2 Node 项目npm 镜像和 PowerShell 权限问题一起解决用 mise 装 Node 的过程很简单mise install node20.18.1 mise use node20.18.1装完以后node -v和npm -v都能立刻用。很多人刚切换过来会惊讶为什么不需要像 nvm 那样重新登录或者 source 一下这就是 shell hook 模式的好处。npm 这边国内开发者最常遇到的问题就是下载依赖太慢。这个和版本管理器无关属于 npm 源的问题可以直接换成国内镜像npm config set registry https://registry.npmmirror.com换完以后npm install的速度会明显改善。如果你们公司内部有私有的 npm 仓库也可以设置成公司源。记住mise 只管“运行时版本”和“环境变量”npm 自身的 registry 配置仍然放在用户目录下的.npmrc里两者并不冲突。另外如果你之前用 nvm 跑过 Windows 环境大概率见过这么一条报错npm : 无法加载文件 D:\node\npm.ps1因为在此系统上禁止运行脚本这是 PowerShell 执行策略导致的和 Node 本身没关系。在 WSL2 里用 mise 基本不会碰到这个问题但如果你还是要在 Windows 侧跑可以管理员身份打开 PowerShell执行Set-ExecutionPolicy RemoteSigned解决。相较之下切换到 WSL2 是一次性地把这个坑绕过去了。4.3 Pythonvenv 虚拟环境和 mise 怎么配合Python 的多版本切换以前用 pyenv 的人都会顺手装一个 pyenv-virtualenv因为需要建虚拟环境管理第三方包依赖。mise 本身不内置 virtualenv 创建能力但它不需要。Python 3.3 以后官方就内置了 venv 模块完全可以替代 pyenv-virtualenv 的常用场景。流程是这样的mise install python3.12.7 mise use python3.12.7 python -m venv .venv source .venv/bin/activate pip install -r requirements.txtmise 负责把python命令指向对应版本的 Python 解释器venv 负责隔离第三方包两者职责非常清晰。唯一要注意的是如果你后来切换了 Python 版本以前创建的.venv很可能基于旧版本的二进制这时候最好删掉重建。这不是 mise 的限制而是虚拟环境的天然特性。我见过不少同学切完 Python 版本后没重建 venv结果python命令版本看起来变了但.venv/bin/python还是旧版本一跑测试全是环境不一致的报错。4.4 JDKJAVA_HOME 再也不用手动改到怀疑人生JDK 的版本管理可以说是三个运行时里最麻烦的。用 nvm 的人是幸福的因为 node 命令本身没有太多额外的环境变量但 Java 不一样很多框架要读 JAVA_HOMEGradle、Maven、Tomcat 都要通过 JAVA_HOME 定位 JDK。以前手动管理 JDK 时每次切版本都要改三个地方PATH、JAVA_HOME、某些 IDE 里单独指定的 JDK 路径稍不留神就跑错版本。mise 对 Java 的处理方式我很喜欢它会通过插件去下载不同发行版的 JDK比如 Adoptium 的 Temurin、Microsoft 的 OpenJDK、Zulu 这些都可以直接安装mise install javatemurin-17 mise use javatemurin-17安装完成并且mise use之后java -version会立刻指向新装的 JDK。JAVA_HOME 这边mise 大多数情况下会自动传给当前 shell 环境。如果你发现某些工具没有正确读到 JAVA_HOME可以在项目根目录的.mise.toml里显式加上[tools] java temurin-17 [env] JAVA_HOME {{config_root}}/.local/share/mise/installs/java/temurin-17这里的模板变量config_root在不同环境会不同建议不要照抄路径而是先执行mise which java查看真实安装位置再根据实际路径去配置。一般来说用 Temurin 发行版时 mise 已经做了很好地自动设置需要你手动写的情况并不多。5. 项目级锁定版本团队协作和 CI 不再各说各话5.1 把运行时版本写进仓库新同事拉下来就能开工一个人自己切换版本只是省时间真正体现统一版本管理价值的场景在团队协作。你想想以前和同事一起排期前端说“我本地是好的啊”后端一查发现同事用的 Node 是另一个版本或者 Python 脚本在本地跑得好好的放到 CI 上因为 Python 版本不同全都崩了。这种问题本质上是大家的运行时环境不一致。用 mise 之后你只需要把.mise.toml提交进 Git 仓库。文件内容类似这样[tools] node 20.18.1 python 3.12.7 java temurin-17 [env] NODE_ENV development新同事把仓库 clone 到本地后进入项目目录执行一条命令mise installmise 会读取.mise.toml把你写明的 node、python、java 版本全部装好然后自动激活。这个体验和以前拿到项目再手动装两三个运行时相比节约的不只是时间更是让人不会漏装某个版本。5.2 CI/CD 和 Docker 里怎么用它保持环境一致CI 环境最大的问题是“缓存”和“可重复性”。以前我在 GitHub Actions 里装 Node 还要单独 action装 Python 又要单独 setup-python装 Java 又是 setup-java三个步骤各管各的。用了 mise 之后CI 流程可以简化成先安装 mise再执行mise install并运行测试。伪代码大概是这样的steps: - uses: actions/checkoutv4 - run: curl https://mise.run | sh - run: mise install - run: mise exec -- npm test - run: mise exec -- python -m pytest你甚至可以进一步把多个测试合并成一个mise run在.mise.toml里定义项目的 tasks但这算进阶用法。对于大部分团队来说只要保证 CI 里第一个步骤能把 mise 装上后面的命令通过mise exec来跑就不会出现“本地一个版本、CI 另一个版本”的问题。Docker 镜像也是一样的道理你可以基于一个干净的 Linux 镜像先装 mise再 COPY 项目的.mise.toml执行mise install。因为在 Docker 里往往会分很多层构建建议把.mise.toml和mise.lock如果生成的话单独 COPY 出来放在项目代码之前这样当项目代码改动但版本没变时Docker 能直接命中缓存构建会快很多。6. 我踩过的一些坑以及遇到问题怎么查6.1 换工具后的第一个大坑PATH 顺序不对命令总是被旧的接管有次我在一台同时装过 pyenv 的机器上切到 mise装好 Python 3.12 后执行python -V跳出来的还是 3.8。我第一反应是 mise 坏了后来才发现是 pyenv 的 init 脚本还在~/.bashrc里它在 mise 之后启动直接把 PATH 盖过去了。这个问题特别容易出现在从老环境迁移到新工具的过程中。解决办法就是回头检查自己的 shell 配置文件把 nvm、pyenv、jenv 相关的初始化行都注释掉只保留mise activate那一行。如果还是不行执行which -a python查看所有解析路径你会很直观地看到是谁在前面拦截了命令。记住工具之间互相抢 PATH 的报错看起来像是“环境坏了”其实多半是“旧配置没清理干净”。6.2 Linux 离线环境装 Node / Python / JDK 怎么办有些生产环境是内网隔离的没法直接访问公网下载运行时。mise 默认也会去公网拉包但我们对离线环境并非完全没有招。最简单的方式是在一台能联网的同架构机器上先把版本装好mise install node20.18.1然后找到安装目录mise where node20.18.1把整个目录打个包传到离线机器的相同路径下再执行mise use node20.18.1。只要版本目录结构一致mise 就能直接识别。另外mise 支持配置镜像源比如 Node 相关的环境变量可以指向你内网放的二进制包地址。不过离线环境本身配置项因企业而异最通用的做法还是“同架构环境拷贝”这个方法在 Python 和 JDK 上也一样有效。6.3 已安装版本越来越多怎么清理和查看用久了以后本地可能会堆积很多大版本比如 Node 12、14、16、18、20 各装几版Python 3.6 到 3.12 也全留着加上 JDK 8、11、17空间占用相当可观。Mise 的清理由mise uninstall来做但你最好是先确认当前项目到底在用哪个版本mise current mise ls如果看到某个版本已经不使用了直接删mise uninstall node18.20.2还有一个小技巧你可以用mise ls --current只看当前目录会生效的版本。这样比全局看一大串列表清爽很多。另外mise 的下载缓存通常在~/.cache/mise或~/.local/share/mise/downloads这样的目录中如果你发现磁盘突然变慢也可以看看是不是缓存包太大。删掉缓存不会影响已安装的版本只是下次安装时需要重新下载。6.4 只想临时跑某版本但不想污染全局配置这是比nvm use更灵活的一个场景。有时候我只想拿某个版本的 Node 跑一下测试脚本但不希望它改变当前项目锁定的版本更不希望把它设成全局默认。mise 提供了一条很顺手的命令mise exec node20.18.1 -- node -v这条命令会在一个子 shell 里临时把 node 指向 20.18.1执行完后面的命令后退出不会修改当前 PATH也不会改.mise.toml。同理你甚至可以这样跑 Pythonmise x python3.11 -- python script.py这种“临时干净环境”的工作方式在排查“是不是版本导致的问题”时特别好用。你不需要切换、不需要记录原来的版本号跑完就恢复原样心理负担极小。6.5 如果你之前已经重度依赖 nvm 的 alias 和版本别名nvm 允许你自己给 Node 版本起别名比如nvm alias default 20有些人还会给某个项目单独设置别名。切到 mise 后这种习惯要改一下。mise 也支持语义化版本前缀比如mise install node20会直接解析到当前最新的 20.x 版本mise use nodelts在某些插件里也支持 LTS 版本标签。但如果你深度依赖旧工程里自定义的 alias那就要先把实际版本号查出来再写到.mise.toml里避免上了别名导致解析不稳定。我个人在实际切换工具时体会最深的一点是不要把 mise 当成“又一个版本管理器”来用而应该把它当成“项目的开发环境描述文件”。以前我们总习惯在个人电脑上手工维护一堆运行时版本换来换去全凭记忆现在有了.mise.toml版本信息跟着代码仓库走任何人拉到项目都能复现出同样环境。这种体验一旦习惯真的很难再回去手动切 nvm 和 pyenv。如果你正准备换统一工具我建议先从某一个新项目开始试把它最核心的 Node、Python、JDK 版本都锁进.mise.toml跑顺之后再慢慢清理旧工具残留路会稳得多。
返回列表