谈谈NPM镜像那些常遇到的坑

目录
文章目录隐藏
  1. 前言
  2. 管理镜像
  3. 遇坑填坑
  4. 源码分析
  5. 坑货小结
  6. 终极总结
  7. 总结

谈谈 NPM 镜像那些常遇到的坑

前言

由于国内网络环境的原因,在执行npm i安装项目依赖过程中,肯定会遇上安装过慢安装失败的情况。有经验的同学通常会在安装完Node时顺便把NPM 镜像设置成国内的淘宝镜像。

npm config set registry https://registry.npm.taobao.org/

这样就能爽歪歪应付大部分npm i的安装情况了。当然,这只是解决了大部分的安装过慢安装失败的情况,随着项目的深入开发,肯定还会遇上一些比较奇葩的情况,这也是笔者为什么要写本文的原因。

管理镜像

你还可能会遇上这种情况,开发项目时使用淘宝镜像,但是发布NPM 第三方模块时就必须使用原镜像了。在着手解决那些奇葩情况前,先推荐大家使用一个NPM 镜像管理工具

  • 原镜像https://registry.npmjs.org/
  • 淘宝镜像https://registry.npm.taobao.org/

主角就是nrm,它是一个可随时随地自由切换NPM 镜像的管理工具。有了它,上面所说的何时使用什么镜像的问题就迎刃而解了。下面对其进行安装并简单讲解如何使用。

安装

npm i -g nrm

查看镜像

nrm ls

增加镜像

nrm add <name> <url>

移除镜像

nrm del <name>

测试镜像

nrm test <name>

使用镜像

nrm use <name>

查看当前镜像

nrm current

熟悉命令后一波操作如下,原镜像淘宝镜像之间随意切换。当然,如果你记性好也不需要用这个工具了,哈哈。

谈谈 NPM 镜像那些常遇到的坑

遇坑填坑

有了nrm切换到淘宝镜像上,安装速度会明显加快,但是遇上安装的模块依赖了C++模块那就坑爹了。在安装过程中会隐式安装node-gypnode-gyp可编译这些依赖C++模块的模块。

那么问题来了,node-gyp在首次编译时会依赖Node 源码,所以又悄悄去下载Node。虽然在前面已设置了淘宝镜像,但是在这里一点卵用都没有。这样又因为国内网络环境的原因,再次遇上安装过慢安装失败的情况。

还好npm config提供了一个参数disturl,它可设置 Node 镜像地址,当然还是将其指向国内的淘宝镜像。这样又能爽歪歪安装这些依赖C++模块的模块了。

npm config set disturl https://npm.taobao.org/mirrors/node/

问题一步一步解决,接下来又出现另一个问题。平常大家都会使用node-sass作为项目开发依赖,但是node-sass的安装一直都是一个令人头疼的问题。

安装node-sass时,在install 阶段会从 Github 上下载一个叫binding.node的文件,而GitHub Releases里的文件都托管在s3.amazonaws.com上,这个网址被 Q 了,所以又安装不了。

然而办法总比困难多,从node-sass的官方文档中可找到一个叫sass_binary_site的参数,它可设置 Sass 镜像地址,毫无疑问还是将其指向国内的淘宝镜像。这样又能爽歪歪安装node-sass了。

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/

其实还有好几个类似的模块,为了方便,笔者还是把它们源码里的镜像参数和淘宝镜像里对应的镜像地址扒出来,统一设置方便安装。以下是笔者常用的几个模块镜像地址配置,请收下!

分别是:SassSharpElectronPuppeteerPhantomSentrySqlitePython

镜像地址配置

npm config set <name> <url>,赶紧一键复制,永久使用。特别注意,别漏了最后面的/

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm config set sharp_dist_base_url https://npm.taobao.org/mirrors/sharp-libvips/
npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
npm config set puppeteer_download_host https://npm.taobao.org/mirrors/
npm config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/
npm config set sentrycli_cdnurl https://npm.taobao.org/mirrors/sentry-cli/
npm config set sqlite3_binary_site https://npm.taobao.org/mirrors/sqlite3/
npm config set python_mirror https://npm.taobao.org/mirrors/python/

有了这波操作,再执行npm i安装以上模块时就能享受国内的速度了。如果有条件,建议把这些镜像文件搬到自己或公司的服务器上,将镜像地址指向自己的服务器即可。在公司内网搭建一个这样的镜像服务器,一直安装一直爽,目前笔者所在的团队就是如此处理。

npm config set electron_mirror https://xyz/mirrors/electron/

源码分析

以经常卡住的node-sass为例,下面是坑爹货node-sass/lib/extensions.js源码部分,可看出它会默认走GitHub Releases的托管地址,上面也分析过原因,在这里就不重复了。

function getBinaryUrl() {
  const site = getArgument("--sass-binary-site")
    || process.env.SASS_BINARY_SITE
    || process.env.npm_config_sass_binary_site
    || (pkg.nodeSassConfig && pkg.nodeSassConfig.binarySite)
    || "https://github.com/sass/node-sass/releases/download";
  const result = [site, "v" + pkg.version, getBinaryName()].join("/");
  return result;
}

而其他模块也有类似的代码,例如puppeteer这个安装Chronium源码部分,有兴趣的同学都去扒一下源码,如出一辙。

async function download() {
  await compileTypeScriptIfRequired();
  const downloadHost =
    process.env.PUPPETEER_DOWNLOAD_HOST
    || process.env.npm_config_puppeteer_download_host
    || process.env.npm_package_config_puppeteer_download_host;
  const puppeteer = require("./index");
  const product =
    process.env.PUPPETEER_PRODUCT
    || process.env.npm_config_puppeteer_product
    || process.env.npm_package_config_puppeteer_product
    || "chrome";
  const browserFetcher = puppeteer.createBrowserFetcher({
    product,
    host: downloadHost,
  });
  const revision = await getRevision();
  await fetchBinary(revision);
  // 还有很多
}

坑货小结

由于node-sass是大家经常使用的项目开发依赖,也是安装时间较长和最常见到报错的模块,在这里笔者就花点篇章分析和解决下可能会遇到的问题。

node-sass安装失败的原因其实并不止上面提到的情况,我们可从安装过程中分析并获取突破口来解决问题。根据npm i node-sass的输出信息来分析,可得到下面的过程。

  • 检测项目node_modulesnode-sass是否存在且当前安装版本是否一致
    • Yes:跳过,完成安装过程
    • No:进入下一步
  • NPM上下载node-sass
  • 检测全局缓存项目缓存中是否存在binding.node
    • Yes:跳过,完成安装过程
    • No:进入下一步
  • Github Releases上下载binding.node并将其缓存到全局
    • Success:将版本信息写入package-lock.json
    • Error:进入下一步
  • 尝试本地编译出binding.node
    • Success:将版本信息写入package-lock.json
    • Error:输出错误信息

不难看出,node-sass依赖了一个二进制文件binding.node,不仅需要从NPM上下载本体还需要从Github Releases上下载binding.node

从实际情况来看,node-sass出现安装过慢安装失败的情况可能有以下几种:

1、NPM 镜像托管在国外服务器

上面有提到,在这里不再叙述,解决办法如下。

nrm use taobao

2、安装过程中悄悄下载node-gyp

上面有提到,在这里不再叙述,解决办法如下。

npm config set disturl https://npm.taobao.org/mirrors/node/

3、binding.node文件托管在国外服务器

上面有提到,在这里不再叙述,解决办法如下。

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/

4、Node 版本与 node-sass 版本不兼容

node-sass版本兼容性好差,必须与 Node 版本对应使用才行,详情请参考node-sass-version-association,复用官方文档的版本对照表,如下。

NodeJS Minimum node-sass version Node Module
Node 14 4.14+ 83
Node 13 4.13+ 79
Node 12 4.12+ 72
Node 11 4.10+ 67
Node 10 4.9+ 64
Node 8 4.5.3+ 57

执行npm i安装依赖前请确保当前的 Node 版本和node-sass版本已兼容。

5、全局缓存中的 binding.node 版本与 Node 版本不兼容

假如本地使用nvmn进行 Node 版本管理,并且已切换了 Node 版本,在安装过程中可能会出现Windows/OS X/Linux 64-bit with Node.js 12.x这样的提示,这种情况也是笔者经常遇上的情况(笔者电脑里安装了 30 多个 Node 版本并且经常来回切换😂)。

这是因为node-sass版本和 Node 版本是关联的(看上面的表格),修改 Node 版本后在全局缓存中匹配不到对应的binding.node文件而导致安装失败。根据错误提示,清理 NPM 缓存且重新安装即可,解决办法如下。

npm cache clean -f

npm rebuild node-sass

所以没什么事就别来回切换 Node 版本了,像笔者装这么多 Node 版本也是逼不得已,老项目太多了😂。

6、安装失败后重新安装

有可能无权限删除已安装的内容,导致重新安装时可能会产生某些问题,建议将node_modules全部删除并重新安装。

在 Mac 系统和 Linux 系统上删除node_modules比较快,但是在 Windows 系统上删除node_modules就比较慢了,推荐大家使用rimraf删除node_modules,一个 Node 版的rm -rf工具。

npm i -g rimraf

在项目的package.json中加入npm scriptsrimraf常驻。三大操作系统通用,非常推荐使用。

{
  "scripts": {
    "reinstall": "rimraf node_modules && npm i"
  }
}

一有什么安装失败重新安装之类的操作,先执行npm run remove删除node_modulesnpm i

npm run reinstall

终极总结

如果看得有点乱,那下面直接贴代码操作顺序,建议前端小白在安装完 Node 后立马处理这些 NPM 镜像问题,防止后续产生不必要的麻烦(解决这些问题是需要花费时间的😂)。

# 查看 Node 版本和 NPM 版本确认已安装 Node 环境
node -v
npm -v

# 安装 nrm 并设置 NPM 的淘宝镜像
npm i -g nrm
nrm use taobao

# 设置依赖安装过程中内部模块下载 Node 的淘宝镜像
npm config set disturl https://npm.taobao.org/mirrors/node/

# 设置常用模块的淘宝镜像
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm config set sharp_dist_base_url https://npm.taobao.org/mirrors/sharp-libvips/
npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
npm config set puppeteer_download_host https://npm.taobao.org/mirrors/
npm config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/
npm config set sentrycli_cdnurl https://npm.taobao.org/mirrors/sentry-cli/
npm config set sqlite3_binary_site https://npm.taobao.org/mirrors/sqlite3/
npm config set python_mirror https://npm.taobao.org/mirrors/python/

针对node-sass的情况:

# 安装 rimraf 并设置 package.json
npm i -g rimraf

# 安装前请确保当前的 Node 版本和 node-sass 版本已兼容

# 安装失败
npm cache clean -f
npm rebuild node-sass 或 npm run reinstall

package.json中加入npm scripts

{
  "scripts": {
    "reinstall": "rimraf node_modules && npm i"
  }
}

总结

NPM 镜像问题的坑确实很多,归根到底还是网络环境导致的。当然这些问题也阻碍不了乐于探索的我们,办法总比困难多,坚持下去始终能找到解决方式。

笔者总结出一个解决这种NPM 镜像问题的好方法,遇到一些上面没有提到的模块,可尝试通过以下步骤去解决问题。

  • 执行npm i前设置淘宝镜像,保证安装项目依赖时都走国内网络
  • 安装不成功时,肯定是在安装过程中该模块内部又去下载了其他国外服务器的文件
  • 在 Github 上克隆一份该模块的源码进行分析,搜索包含base、binary、cdn、config、dist、download、host、mirror、npm、site、url等这样的关键词(自行探索,通常mirror的匹配度最高)
  • 在搜查结果里查找形态像镜像地址的代码块,再分析该代码块的功能并提取最终的镜像地址,例如node-sasssass_binary_site
  • 去淘宝镜像官网、百度、谷歌等网站查找你需要的镜像地址,如果实在找不到就规范上网把国外服务器的镜像文件拉下来搬到自己或公司的服务器上
  • 设置模块依赖的镜像地址:npm config set <registry name> <taobao url / yourself url>
  • 重新执行npm i安装项目依赖,大功告成

如果以上内容帮不了你或在解决NPM 镜像问题上还遇到其他坑,欢迎添加笔者微信一起交流。如有错误地方也欢迎指出,如有更好的解决方法也可提上建议。

原文链接:点击这里

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 谈谈NPM镜像那些常遇到的坑

发表回复