注:文中 mac arm64、apple silicon、m1 皆指代采用 Apple 自研芯片的 mac。
早前我把自己的 Nodejs 版本管理工具切换到了 fnm,比 nvm 更快更简洁,比 n 更灵活是我选择它的原因。
不久前我的 mac 更新为了 m1 芯片的版本,随之而来的开发环境的问题也很多。
首先就是 Nodejs 的问题。
Nodejs 的 mac arm64 支持现状
截止本文发布时间(2021-1-20),只有 v15.x 版本的 Nodejs 支持了 arm64 版本的 mac 系统,其余版本的 Nodejs 只能通过 Rosetta 运行(不过问题不多)。
在 m1 芯片能够提供极大程度性能提升的情况下,大家当然希望更多版本的 Nodejs 可以原生支持 arm64 的 mac。
不过目前 Nodejs 官方还没有正式宣布支持 apple silicon(另一个链接),距离正式支持应该还有一段时间。
由于以上原因,fnm 在 mac arm64 下的使用也产生了一些问题。
在给项目提交了一次更新之后,目前 fnm 已经可以在 mac arm64 下正常编译。
由此,fnm 在 mac arm64 下会去尝试从 Nodejs 官方网站下载 darwin-arm64
版本的预编译二进制包。但是因为官方还没有提供这一版本的包,所以 fnm 无法正常工作。
我的 fnm 临时解决方案
由于这个问题,我只能采用一个临时解决方案(不准备切换回 nvm 或者 n 了)。
方案大致逻辑是:
- v15.x 的 Nodejs 我需要使用 mac arm64 的版本(性能提升显著,为什么不呢)
- 其余更低版本的 Nodejs 使用 x64 版本通过 Rosetta 运行
确定了基础逻辑之后,我需要先找一个获得 mac arm64 版本的方法,从源码编译是一种选择,这也是 nvm 的方法,不过手动编译效率有些低下。好在 homebrew 已经提供了arm64 的预编译包(homebrew 提供预编译包的方式),从 homebrew bottles 下载是一个不错的选择。
步骤
-
首先我们正常初始化 fnm
我同时使用 fnm 的 mac arm64 和 x64 版本,使用 x64 版本安装 x64 版本的 Nodejs,使用 arm64 版本做其余逻辑。
-
安装 arm64 版本的 Nodejs
大致流程就是从 homebrew bottles 下载
darwin-arm64
版本的 Nodejs 预编译包,按照 fnm 的文件结构把文件放到相应位置,比如15.6.0
对应~/.fnm/node-versions/v15.6.0/installation
。
这样 fnm 就可以同时管理 x64 和 arm64 版本的 Nodejs 了。
为了方便我获取 arm64 版本的 Nodejs,我写了一个 shell 脚本,从 homebrew bottles 下载最新的 darwin-arm64
Nodejs 包。
#!/bin/bash
# 假设你已经安装了 homebrew, wget 和 fx(https://github.com/antonmedv/fx)
# 所有工作在 /tmp 下完成避免意外情况
mkdir -p /tmp/fnm-node;
pushd /tmp/fnm-node;
rm -fr ./*;
mkdir fnm;
# 保存 homebrew 提供的 node 信息
NODE_INFO=./tmp_node_info.json;
brew info node --json > ${NODE_INFO};
# 获取最新的 Node 版本
NODE_VERSION=$(fx $NODE_INFO .[0].linked_keg);
echo "nodejs version: ${NODE_VERSION;}";
# 建立 fnm 的相同文件结构
mkdir -p ./fnm/node-versions/v${NODE_VERSION}/installation;
# bottles 上的 Node 包
NODE_TAR=$(fx $NODE_INFO .[0].bottle.stable.files.arm64_big_sur.url)
# sha256
TAR_SHA256=$(fx $NODE_INFO .[0].bottle.stable.files.arm64_big_sur.sha256)
# 本地的包文件
NODE_TAR_FILE="node-${NODE_VERSION}.arm64_big_sur.bottle.tar.gz"
# 下载包
wget ${NODE_TAR};
# 校验 sha256
FILE_SHA=$(shasum -a 256 ${NODE_TAR_FILE} | head -c 64);
if [[ "$FILE_SHA" != "$TAR_SHA256" ]]; then
echo "sha256 check failed";
exit 1;
fi
# 解压
tar xzf ${NODE_TAR_FILE};
# 移动文件到 fnm 镜像结构
mv node/${NODE_VERSION}/* ./fnm/node-versions/v${NODE_VERSION}/installation;
# 安装npm和npx
pushd ./fnm/node-versions/v${NODE_VERSION}/installation;
cp -r libexec/lib/node_modules ./lib;
ln -sf ../lib/node_modules/npm/bin/npm-cli.js ./bin/npm;
ln -sf ../lib/node_modules/npm/bin/npx-cli.js ./bin/npx;
rm -fr AUTHORS etc INSTALL_RECEIPT.json libexec share;
popd;
# 创建 fnm 的文件夹结构(可能还没有安装过node)
mkdir -p ~/.fnm/node-versions;
# 移动最终文件到 fnm 的真正文件夹中
mv ./fnm/node-versions/v${NODE_VERSION} ~/.fnm/node-versions;
popd;
echo "all things done";
fnm ls;
执行完之后,fnm 就获得了当前 homebrew 中最新的 arm64 版本的 Nodejs。
根据你的本地配置修改脚本中的相应参数。
GitHub gist: fnm: install arm64 version of node from homebrew bottles
期待 Nodejs 早日正式支持 mac arm64,以及更多 lts 版本的支持。