本来,前两天我就想发这个帖子,因为我一直在坑里,好不容易跳出坑了,觉得应该分享下:
墙,是程序员的一个大坑。nodejs本身的版本管理,是Nodejs使用的另一个坑。直到看到本站fengmk2 同学的 快速搭建 Node.js 开发环境以及加速 npm ,我眼前一亮, nvm + 淘宝镜像,近乎完美的把这两个坑给堵住了。于是我在思考,这种方法叫最佳实践,有一种鲜明的特点,当你不用它的时候,好像也没什么,当你用上了之后,觉得再也不想回到不用它的状态中去了(有点像《三体》中人进入四维空间,就不想回到三维空间中的那种感觉)。回到这个例子,不用nvm,在OSX上,我一直是去官网下载pkg包来安装升级node版本的,某次不小心也安装了一次n,但很快忘了。这种方法会有一个痛苦,那就是 node_modules 目录得重新安装一遍,local的还好,global的,真烦。用了nvm,好家伙,每个版本及其node_modules目录形成单独的“闭包”,问题完美解决。又如淘宝镜像,你不用的话国家防火墙时不时骚扰你真的是痛苦之极,用了之后就再也没有理由切换回来了。
最佳实践的另一个特点,那就是对初学者来说,不知道去哪找。于是每个人在遇到困难的时候,都希望得到一个有经验的人的帮助。所以,我们应该分享最佳实践,感谢 fengmk2同学的分享!
本来我就想写这些,但是昨天我掉进了另一坑,推迟了本文的发出。警告:后文有些长,没兴趣就别看了。
那个坑很诡异,我一直使用的ionic突然不能编译 所有的 项目了,报一个错:
PhaseScriptExecution Copy\ www\ directory build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh cd /Users/zzb/clio/platforms/ios /bin/sh -c /Users/zzb/clio/platforms/ios/build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh /Users/zzb/clio/platforms/ios/build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh: line 2: 12179 Killed: 9 node cordova/lib/copy-www-build-step.js Command /bin/sh failed with exit code 137
** BUILD FAILED **
大约是一周前还好好的,怎么突然出了个这个错误呢?无论使用命令行还是在Xcode中编译,都同样报错。在 痛苦 绝望 (其实这种感觉回想起来,就是乐趣)之中,我思考各种可能:
- cordova从5.3.3升级到5.4.0了
- cordova-ios从3.9.1升级到3.9.2了
不过,返回旧版本(感谢淘宝镜像!)问题依旧。因此排除。
被信号9杀死,我想可能是OOM了,重启一下计算机试试,涛声依旧!
好吧,模拟一下程序的执行:
zmb:ios zzb$ pwd /Users/zzb/clio/platforms/ios zmb:ios zzb$ ./build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh ./build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh: line 2: 12615 Killed: 9 node cordova/lib/copy-www-build-step.js zmb:ios zzb$
问题简单复现。Google下,找到了 这个 issue CB-9273 ,不过已经fix了。查看一下脚本的内容:
zmb:ios zzb$ cat ./build/clio.build/Debug-iphonesimulator/clio.build/Script-304B58A110DAC018002A0835.sh #!/bin/sh NODEJS_PATH=/usr/local/bin; NVM_NODE_PATH=~/.nvm/versions/node/
nvm version 2>/dev/null
/bin; N_NODE_PATH=find /usr/local/n/versions/node/* -maxdepth 0 -type d 2>/dev/null | tail -1
/bin; XCODE_NODE_PATH=xcode-select --print-path
/usr/share/xcs/Node/bin; PATH=$NODEJS_PATH:$NVM_NODE_PATH:$N_NODE_PATH:$XCODE_NODE_PATH:$PATH && node cordova/lib/copy-www-build-step.js
发现一个岔路问题,我的nvm是安装在 ~/nvm 下而不是 ~/.nvm 下的(也不是 fengmk2 同学的 ~/git/nvm )。于是我做了一个软链接让 ~/.nvm 指向 ~/nvm ,问题依旧!
好吧,拆开揉碎了,再次模拟:
zmb:ios zzb$ NODEJS_PATH=/usr/local/bin; NVM_NODE_PATH=~/.nvm/versions/node/
nvm version 2>/dev/null
/bin; N_NODE_PATH=find /usr/local/n/versions/node/* -maxdepth 0 -type d 2>/dev/null | tail -1
/bin; XCODE_NODE_PATH=xcode-select --print-path
/usr/share/xcs/Node/bin; PATH=$NODEJS_PATH:$NVM_NODE_PATH:$N_NODE_PATH:$XCODE_NODE_PATH:$PATH zmb:ios zzb$ which node /Users/zzb/.nvm/versions/node/v0.12.7/bin/node zmb:ios zzb$ node cordova/lib/copy-www-build-step.js path.js:488 throw new TypeError(‘Arguments to path.join must be strings’); ^ TypeError: Arguments to path.join must be strings at Object.posix.join (path.js:488:13) at Object.<anonymous> (/Users/zzb/clio/platforms/ios/cordova/lib/copy-www-build-step.js:37:19) at Module._compile (module.js:460:26) at Object.Module._extensions…js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3 zmb:ios zzb$
错误不一样了!不过这个错误,通过代码看起来倒是正常的,因为我没有在Xcode环境中编译,或者通过 ionic build ios来编译。
写这个文章的时候,我确实已经无法 更直接 复现那个信号9了(奇怪),但是因为这个问题已经解决,我直接揭晓问题本身:
/usr/local/n/versions/node/0.12.7/node
是没有下载完成的二进制文件。正常文件大小约18M,这个文件是9.8M。我二进制比较了下,是截断的。在某次调试中,我发现 which node 指向这个文件,因此我掉进坑了。把 /usr/local/n 移走,问题解决。
在解决了这个问题后我反思了下:
- n与nvm相比,不好(虽然我这里说的不好与我的问题无关)
- 我恨国家防火墙!
- .nvm 目录位置,这里有两个细节,第一,CB9273 的solution里面,~/.nvm 是固定位置,能不能不固定?第二,fengmk2的分享,要是放在 ~/.nvm 就好了。关于这个问题可进一步讨论。
我写这个坑与其解决过程与最佳实践有什么关系呢?我想表达的是, 如果一个新手,上来就采用最佳实践,掉进坑里的概率会小很多。 我掉进这个坑是与多个因素相关联的,因此除了我,很难有第二个人会掉进这个坑:
- 假如我从来没有安装过n
- 假如我上来就用nvm
- 假如n下载的那个node是完整的
好吧,本文完,谢谢看到这里的朋友。