or

记一次npm包的安装收获

2019年6月7日
端午节快乐哇!假期这么宝贵,还不用来敲码放松放松(滑稽.jpg) ~

在使用nodejs的过程中,最让我痛心和畏惧的就是module的安装了:

一种情况是,在安装某个module时,它的readme里列出了很多其他的必须配置项,自己辛辛苦苦的按要求配好了,再次安装时依旧一堆报错。这时只能再去认真阅读readme,看看是不是漏了什么,以及认真查看报错信息。

另一种情况就是npm i之后,命令行里出现的的ETIMEOUTECONNRESET等错误码,这种情况大多都是网络问题导致,解决办法也是不唯一的,大多是清理npm缓存(npm cache clean --force),或尝试切换科学工具,如果错误依在,不妨试试佛系解决方案:关机睡觉,第二天起床后再试。


今天兴致勃勃想要(再)玩一玩tensorflow,它提供了浏览器端接口,也有node的接口。我是更喜欢后端环境的,所以就用node端接口咯。因为之前也有安装过这个包,没啥问题直接成功,于是这次也是满心欢喜的在命令行中输入yarn add @tensorflow/tfjs-node,唰唰唰,yarn的安装速度真的是快哇,过了一会发现,命令行一直悬停在了这里:

[4/4] Building fresh packages...
[1/1] ⢀⢀ @tensorflow/tfjs-node

我以为是墙太高了,于是把梯子伸长了一波(切换为全局模式),然后删除node_modules目录重试,发现依旧卡住那里,内心很懵逼啊,错也不报,到底出了嘛问题?

尝试用npm来下载,输入npm i @tensorflow/tfjs-node --save,哇----噻---还是卡住了😅,不过这下我起码知道为啥卡住了,下面是命令行显示的内容:

> node scripts/install.js
* Downloading libtensorflow

原来是在下载一个文件啊,我用yarn安装竟然都没这个提示😭,所以说个题外话:yarn和npm并没有谁更好之说,当module安装出现了问题,就去尝试用另一个来安装,或许就能从命令行中获取到更多有用的信息来指明到底哪里出了问题。

现在问题知道了,就是下载libtensorflow这个文件时请求始终无响应,导致一直处于等待状态,这个时候需要去查看这个包的源码中与这个文件下载相关的代码:

.../node_modules/@tensorflow/tfjs-node/scripts/install.js中找到了文件的下载url是https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-windows-x86_64-1.13.1.zip

我将其粘入浏览器,发现是可以下载这个文件的(表明我的墙是翻得过去的),为啥命令行里就不行呢?

查看.../node_modules/@tensorflow/tfjs-node/scripts/resources.js中知,下载请求是通过调用nodejshttps模块进行的,然而nodejs默认是会忽略系统代理直接和目标地址连接的,所以老是爬不上来我的梯子,就挂在那里咯。

所以现在要解决的就是让请求走本地代理。

查看.../scripts/resources.js中的代码,会发现下面一段内容:

async function downloadAndUnpackResource(uri, destPath, callback) {
  // If HTTPS_PROXY, https_proxy, HTTP_PROXY, or http_proxy is set
  const proxy = process.env['HTTPS_PROXY'] || process.env['https_proxy'] ||
      process.env['HTTP_PROXY'] || process.env['http_proxy'] || '';

哇塞,原来这个包已经处理了可能会用到代理的情况,因为没设置相关的环境变量,导致没用上代理。

发现新大陆的我,赶紧在命令行中敲入了set http_proxy=http://127.0.0.1:8080,然后再次重新安装。人生总是一波三折,还是没有成功,what happened?又看了看源码,我勒个去:

async function downloadAndUnpackResource(uri, destPath, callback) {
  // If HTTPS_PROXY, https_proxy, HTTP_PROXY, or http_proxy is set
  const proxy = process.env['HTTPS_PROXY'] || process.env['https_proxy'] ||
      process.env['HTTP_PROXY'] || process.env['http_proxy'] || '';
  const options = {...url.parse(uri), agent: https.globalAgent};  if (proxy !== '') {
    options.agent = new HttpsProxyAgent(proxy);
  }
  const request = https.get(uri, response => {    //...
  })
}

上面代码中会发现,options变量根本没有传入给https.get方法呀,我内心小激动着,可以去提issue咯,打开它的github,找到相应的源文件一看,我勒个又去,源文件里的options变量已经传给了https.get,和npm包里明显不一致啊,难道是新版本还没发布?于是再看了眼repo的package.json,发现版本和npm目前的发布版(v1.1.2)是对应的,看样子是开发人员粗心了吧。那这该如何解决呢,难道自己fork仓库再发布一波?

可别忘了,npmyarn都是可以直接从github安装的,输入npm i https://github.com/tensorflow/tfjs-node --save(记得先设置环境变量哦),完美,安装成功😱!!

快去吃点粽子庆祝庆祝,等等,你好像花了这么长时间连个实际代码还没敲...啊呀,过节就要有过节的样子,怎么能敲代码呢😝


再次回顾这次“事件”,发现也并不是什么很大的问题,对我来说收获更大是由这个事情而引申出的其它内容:虽然上面那个包提供了走代理相关的配置,但自己很想知道具体细节,所以是有去狗狗"nodejs request through proxy"相关的内容,看了很多答案和文章,也刷新了我对net,http(s)等模块的认识。自己平时用nodejs都是直接用框架,然而框架把很多底层细节都封装了,所以很难学习到偏底层的知识,所以通过这件事我再次告诉自己:想成为一个真正的nodejs developer吗?扔掉框架,自己造轮子吧!(妈呀,宏图大展,加油哦,看好自己!)

or