返回文章

node-sass 安装失败:not a mach-o file / distutils 报错怎么修

最近装一个老项目依赖,node-sass 又炸了。

看起来是两个报错:

not a mach-o file

还有一个:

ModuleNotFoundError: No module named 'distutils'

这两个错误连在一起,很容易把人绕晕。

说人话就是:

先下载到了一个坏的 binding.node 文件,不能用;然后它想本地编译,结果你的 Python 太新,老的构建工具又跑不起来。


问题现象

node-sass 安装时会先下载一个预编译好的二进制文件。

这个文件一般叫:

binding.node

正常情况下,它应该是一个真正的 native binary。

但这次下载到的东西是坏的。可能是 npm 镜像、代理、缓存出了问题,把一个 404 页面或者错误响应当成了 binding.node 缓存下来。

于是 macOS 加载它的时候就会报:

not a mach-o file

意思是:

你让我加载一个 macOS 二进制文件,但这个文件根本不是二进制文件。

所以第一层问题是:下载到的 binding.node 是坏的。


真正原因

node-sass 的安装逻辑大概是这样:

先下载预编译 binary
        ↓
下载失败或文件坏了
        ↓
改成本地编译
        ↓
调用 node-gyp
        ↓
node-gyp 调 Python
        ↓
Python 3.12+ 没有 distutils
        ↓
安装失败

所以这不是一个单点问题,而是两个问题叠加:

  1. binding.node 下载坏了;
  2. fallback 到本地编译时,Python 3.12+ 又不兼容老版本 node-gyp。

distutils 以前是 Python 里的一个构建相关模块。老版本 node-gyp 会依赖它。

但 Python 3.12 之后,distutils 没了,所以就报:

ModuleNotFoundError: No module named 'distutils'

怎么修

按优先级来,不要一上来乱改。

1. 先重新下载正确的 binary

先清缓存:

rm -rf node_modules
rm -f package-lock.json
npm cache clean --force

然后换一个可用的 node-sass binary 地址:

SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass npm install

如果只是镜像缓存坏了,这一步通常就够了。


2. 如果还失败,就指定 Python 3.11

如果 binary 还是下不下来,node-sass 会尝试本地编译。

这时不要用 Python 3.12+,改用 Python 3.11。

先找到 Python 3.11 路径:

which python3.11

然后告诉 npm 使用它:

npm config set python /path/to/python3.11

例如 macOS Homebrew 可能是:

npm config set python /opt/homebrew/bin/python3.11

再重新安装:

rm -rf node_modules
npm install

这一步解决的是:本地编译时 Python 版本不兼容的问题。


3. 长期方案:迁移到 sass

如果这个项目还会继续维护,最好别继续跟 node-sass 纠缠。

直接迁移到 Dart Sass,也就是 npm 包里的 sass:

npm uninstall node-sass
npm install sass

如果项目里必须保留 node-sass 这个包名,也可以用 npm alias:

{
  "node-sass": "npm:sass@^1.77.0"
}

不过更推荐直接改成:

{
  "sass": "^1.77.0"
}

原因很简单:

sass 不依赖 native binary,也就不会再被 Python、node-gyp、CPU 架构、npm mirror 这些东西卡住。


我的建议

短期修复:

rm -rf node_modules
rm -f package-lock.json
npm cache clean --force
SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass npm install

如果还不行:

npm config set python /path/to/python3.11
npm install

长期修复:

npm uninstall node-sass
npm install sass

这次问题的核心其实就一句话:

not a mach-o file 是 binary 坏了;No module named distutils 是 fallback 编译时 Python 太新了。

所以别只盯着 Python,也别只盯着 npm。

真正的问题是:

坏的 node-sass binary + 老的 node-gyp 构建链 + Python 3.12 兼容性问题

能救急就先换 binary。

要长期稳定,就迁移到 sass。