yarn install 超时

Published on
发布于·预估阅读7分钟
Authors
  • Name
    willson-wang
    Twitter

问题1 trouble with your network connection

针对 yarn 1.x版本在CI场景安装依赖的过程中出现 There appears to be trouble with your network connection. Retrying... 这样的提示,如下图所示 image.png

最终导致安装过程无限拉长,或者导致安装失败

针对这个问题,应该怎么去排查与解决

首先导致这个问题的原因是yarn 在install的时候,无法正确获取到tarball对应的tgz包,如下图所示 image.png

无法正确获取到tgz包的原因则是网络问题,因为我们是从npm官方源或者yarn源上获取的这些tgz包,而这些源都是国外服务

获取安装超时包

第一步:在yarn install命令上添加--verbose命令行参数,目的是打印install整个过程中日志

// 添加上--verbose参数
yarn --ignore-optional --frozen-lockfile --check-files --verbose

具体日志如下图所示,可以看到详细的请求日志 image.png

第二步:查看添加参数之后的日志

gitlab流水看日志 image.png

第三步:使用下面的函数,获取下载的tgz包 为什么要这一步,原因是就是加上--verboseyarn输出的详细日志也只会有There appears to be trouble with your network connection. Retrying... 这样的打印,是看不出哪个包超时加载的,所以需要我们手动获取一下tgz包来判断是哪些包超时加载了

gitlab 流水日志查看超时包

function logPkg(txt) {
  const map = new Map()
  const result = txt.matchAll(/http.*?\.tgz/g);
  for (let item of result) {
    const pkg = decodeURIComponent(item[0])
    if (map.has(pkg)){
      map.get(pkg).push(pkg)
      console.log(`当前npm包${pkg}属于超时安装`, map.get(pkg));
    } else {
      map.set(pkg, [pkg])
    }
  }
}

// 获取到全部日志的内容,并传入logPkg
logPkg(document.getElementsByTagName('pre')[0].innerHTML)

如果有超时安装的包,控制台会直接打印出对应的包 image.png

解决方法

使用淘宝源

问题2 卡在building fresh packages....

针对 yarn 1.x版本在CI场景安装依赖的过程中出现 building fresh packages... 这样的提示,如下图所示 image.png

最终导致install失败,或者install时间过长

如果在CI场景如果无法查看全部日志,可以通过grep过滤输出,如下所示

yarn install --verbose |grep -v 'Copying' |grep -v 'Creating'
OR
yarn install --verbose |grep -v 'Copying\|Creating'

针对这个问题,应该怎么去排查与解决

首先导致这个问题的原因是yarn在将tgz包拉取到全局缓存目录,并将全局缓存目录内的包 copy到当前项目目录的node_modules之后,会执行npm包内的install、postinstall等钩子,而有些npm包是会利用install、postinstall钩子做一些下载文件的操作,比如node-sass,如下图所示

定义了install与postinstall钩子 image.png

定义默认的文件获取路径,为github地址 image.png

执行下载文件的操作 image.png

这些包内的默认的下载地址都是国外的服务器地址,由于网络的问题,很容易导致超时,最终导致install失败

获取安装超时的文件

怎么知道项目内的哪些包在install等钩子内去下载依赖,可以按照下面的操作进行

在yarn install命令上添加--verbose命令行参数,目的是打印install整个过程中日志

// 添加上--verbose参数
yarn --ignore-optional --frozen-lockfile --check-files --verbose

具体日志如下图所示,可以看到详细的请求日志 image.png

从日志可以看到下载超时的文件

解决方法

设置针对上述问题,有通用的解决方法,就是允许通过专门的字段指定下载地址,比如node-sass这个包,可以通过sass_binary_site指定文件下载路径,常用的需要指定文件下载路径的包,如下所示

方式1: 设置.npmrc

sass_binary_site=https://npmmirror.com/mirrors/node-sass
sentrycli_cdnurl=https://npmmirror.com/mirrors/sentry-cli
electron_mirror=https://npmmirror.com/mirrors/electron
chromedriver_cdnurl=https://npmmirror.com/mirrors/chromedriver
operadriver_cdnurl=https://npmmirror.com/mirrors/operadriver
selenium_cdnurl=https://npmmirror.com/mirrors/selenium
puppeteer_download_host=https://npmmirror.com/mirrors
grpc-node-binary-host-mirror=https://npmmirror.com/mirrors

方式2: 通过npm config set设置

npm config set sass_binary_site https://npmmirror.com/mirrors/node-sass
npm config set sentrycli_cdnurl https://npmmirror.com/mirrors/sentry-cli
npm config set electron_mirror https://npmmirror.com/mirrors/electron
npm config set chromedriver_cdnurl https://npmmirror.com/mirrors/chromedriver
npm config set operadriver_cdnurl https://npmmirror.com/mirrors/operadriver
npm config set selenium_cdnurl https://npmmirror.com/mirrors/selenium
npm config set puppeteer_download_host https://npmmirror.com/mirrors
npm config set grpc-node-binary-host-mirror https://npmmirror.com/mirrors

FAQ

为什么安装项目依赖之前已经设置了源,为什么实际安装的时候,还有包不是从设置的源安装

"set_registry": "npm config set registry https://registry.npmmirror.com/"

原因是:yarn 1.x设计上的缺陷,为了保证复用缓存与方便提升依赖,生成的yarn.lock内是直接包含了registry的,如下图所示 image.png 而yarn在install的时候,如果有yarn.lock,那么则会直接使用yarn.lock内的链接来直接安装 比如jsonwebtoken这个包,虽然设置了指定的源,但是yarn.lock内获取tgz的地址是https://registry.npmjs.org/所以这个包就还会从npm官方源安装,而不是从指定源安装

怎么从根上避免这个问题,可以查看下一篇,自定义Node镜像