注册
web

又报gyp ERR!为什么有那么多人被node-sass 坑过?

前言


node-sass: Command failed.gyp ERR! build error 这几个词相信很多小伙伴一定看着眼熟,当你的终端出现这些词时那么毫无疑问,你的项目跑不起来了。。。。。。


你可能通过各种方式去解决了这个报错,但是应该没有人去深究到底是咋回事,接下来让我们彻底弄懂,再遇到类似问题时能够举一反三,顺利解决。


关键词:node-sass libsass node-gyp


先来看个截图感受一下


image.png


image-1.png


熟悉吧?截图里我们看到了几个关键词 node-sass libsass node-gyp .cpp,我们一一来解释一下


node-sass


node-sass 是一个用于在 Node.js 中编译 Sass 文件的库,node-sass 可以将 .scss 或 .sass 文件编译为标准的 .css 文件,供浏览器或其他工具使用。



  • node-sass 可以看作是 libsass 的一个包装器(wrapper)或者说是 nodejs 和 libsass 之间的桥梁。
  • 它提供了一个 Node.js 友好的接口来使用 libsass 的功能。
  • 当你使用 node-sass 时,实际的 Sass 编译工作是由底层的 libsass 完成的。

当你的项目中使用 sass 来写样式时,会直接或间接地引入这个这个库。


libsass


一个用 C++ 编写的高性能 Sass 编译器,这就是为什么你能在终端日志中看到 .cpp 的文件。


注意,搞这么麻烦就是为了高性能编译sass。


node-gyp


node-sass引入了 c++ 编写的库,那么直接在 node 中肯定是使用不了的,毕竟是两种不同的语言嘛,那么就需要 node-gyp 登场了。


node-gyp 是一个用于编译和构建原生 Node.js 模块的工具,这些原生模块通常是用 C++ 编写的。


node-sass 需要在安装时编译 libsass 的 C++ 代码,以生成可以在本地机器上运行的二进制文件。在这个编译过程中,node-gyp 就被用作构建工具,它负责调用 C++ 编译器(如 g++ 或 clang++),并将 libsass 的源代码编译为与当前系统兼容的二进制文件。


node-gyp 本身是一个用 JavaScript 编写的工具。它使用 Node.js 的标准模块(如 fs 和 path)来处理构建和配置任务,但是需要一些外部工具来实际进行编译和构建,例如 make、gcc等,这些工具必须安装在系统中,node-gyp 只是协调和使用这些工具。


普通模块(JavaScript/TypeScript)


普通模块是用 JavaScript 或 TypeScript 编写的,Node.js 本身可以直接执行或通过编译(如 TypeScript 编译器)转换为可执行代码,Node.js 使用 V8 引擎执行 JavaScript 代码。


原生模块(C/C++ 编写)


原生模块是用 C/C++ 编写的代码,这些模块通常用于高性能需求或需要直接与底层系统 API 交互的场景。它们通过 node-gyp 进行编译,并在 Node.js 中以二进制文件的形式加载。


例如以下模块:



  • node-sass:编译 Sass 文件,依赖 libsass 进行高性能的样式编译。
  • sharp:处理图像文件,使用 libvips(c++库) 提供高效的图像操作。
  • bcrypt:进行加密处理,提供安全的密码哈希功能。
  • fsevents:用于 macOS 系统的文件系统事件监听。

许多现有的高性能库和工具是用 C++ 编写的。为了利用这些库的功能,Node.js 可以通过模块接口调用这些 C++ 库,尤其某些高级功能,如加密算法、图像处理等,已经在 C++ 中得到了成熟的实现,Node.js 可以直接集成这些功能,而不必再重新造轮子而且性能还肯定不如用 c++ 写的库。



所谓的原生模块接口就是 node-gyp(还有Node-API (N-API)等),感兴趣的可以看看 node-gyp 的实现,或者了解下包信息 npm info node-gyp



node-gyp 基于 gyp,并在其之上添加了 Node.js 特定的功能,以支持 Node.js 模块的编译。


gyp


gyp(Generate Your Projects)是一个用于生成构建配置文件的工具,它负责将源代码(C++ 代码)转换为特定平台的构建配置文件(如 Makefile、Visual Studio 项目文件等),生成构建文件后,使用生成的构建文件来编译项目。例如,在 Unix 系统上,运行 make;在 Windows 上,使用 Visual Studio 编译项目。



从前端的角度来看,你可以把gyp理解成 webpack,而 make 命令则是 npm run build



为什么报错?


现在,我们已经了解了一些基本概念,并且知道了c++原生模块是需要在安装时编译才能使用的,那么很明显,上面的错误就是在编译时出错了,一般出现这个错误都是因为我们有一些老的项目的 node 版本发生了变化,例如上面的报错就是,在 node14 还运行的好好的,到了 node16 就报错了,我们再来看一下报错细节


image-2.png


这个错误发生在编译 node-sass 的过程中,具体是在编译 binding.cpp 文件时。
binding.cpp 是 node-sass 的一部分,用于将 libsass 与 Node.js 接口连接起来。


报错发生在 v8-internal.h 文件里,大概意思是这个c++头文件里使用了比较高级的语法,node-sass中的c++标准不支持这个语法,导致报错,就相当于你在 js 项目里引入一个三方库,这个三方库使用了 es13 的新特性(未编译为es5),但是你的项目只支持 es6,从而导致你的项目报错。


所以解决思路就很清晰了,要么降级 node 版本,要么升级 node-sass,要么干脆就不用node-sass了


解决方案


rebuild 大法


npm rebuild node-sass 重新编译模块,对于其他编译错误该方法可能会有效果,但是如果 node-sass 和 node 版本不匹配那就没得办法了,适合临时使用,不推荐。


升级node-sass


以下是 node-sass 支持的最低和最高版本的指南,找对应的版本升级就好了


image-3.png


但是!node-sass 与node版本强绑定,还得去想着保持版本匹配,心智负担较重,所以使用 sass 更好


更换为 sass


官方也说了,不再释放新版本,推荐使用 Dart Sass
image-4.png


Sass 和 node-sass 的区别


实现语言:



  • Sass:Sass 是一个用 Ruby 编写的样式表语言,最初是基于 Ruby 的实现(ruby-sass)。在 Ruby 版本被弃用后,Sass 社区推出了 Dart 语言实现的版本,称为 dart-sass。这个版本是当前推荐的实现,提供了最新的功能和支持。
  • node-sass:node-sass 封装了 libsass,一个用 C++ 编写的 Sass 编译器。node-sass 使用 node-gyp 编译 C++ 代码和链接 libsass 库。

构建和编译:



  • Sass:dart-sass 是用 Dart 语言编写的,直接提供了一个用 JavaScript 实现的编译器,因此不需要 C++ 编译过程。它在 Node.js 环境中作为纯 JavaScript 模块运行,避免了编译问题。
  • node-sass:node-sass 依赖于 libsass(C++ 编写),需要使用 node-gyp 进行编译。很容易导致各种兼容性问题。

功能和维护:



  • Sass:dart-sass 是 Sass 的官方推荐实现,拥有最新的功能和最佳的支持。它的更新频繁,提供了对最新 Sass 语言特性的支持。
  • node-sass:由于 node-sass 依赖于 libsass,而 libsass 的维护在 2020 年已停止,因此 node-sass 逐渐不再接收新的功能更新。它的功能和特性可能滞后于 dart-sass。

性能:



  • Sass:dart-sass 的性能通常比 node-sass 更佳,因为 Dart 编译器的性能优化更加现代。
  • node-sass:虽然 libsass 在性能上曾经表现良好,但由于它不再更新,可能不如现代的 Dart 实现高效。

总结


gyp ERR!node-sass 问题是由 node-sass 与 node 版本兼容引起的编译问题,推荐使用 sass 替代,如果老项目不方便改的话就采用降级 node 版本或升级 node-sass 的办法。


其实这种问题没太大必要刨根究底的,但是如果这次简单解决了下次遇到类似的问题还是懵逼,主要还是想培养自己解决问题的思路,再遇到类似天书一样的坑时不至于毫无头绪,浪费大量时间。


作者:Pursue_LLL
来源:juejin.cn/post/7408606153393307660

0 个评论

要回复文章请先登录注册