Macのrbenvでインストールエラー
久しぶりにrbenvでRuby2.3.0をインストールしようとしたところ、エラーでインストールできなかった。 OpenSSLとcurlのバージョンを上げることでインストールできるようになった。
環境
rbenv installで出たエラー
$ rbenv install 2.3.0 ruby-build: use openssl from homebrew Downloading ruby-2.3.0.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.0.tar.bz2 error: failed to download ruby-2.3.0.tar.bz2 BUILD FAILED (OS X 10.12.6 using ruby-build 20180424-3-g16ac342)
対応
- OpenSSLとcurlのバージョンを上げる。
Googleで検索すると、Linuxでの同様のエラーがすでに報告されているようだが、Macでも同様の対応方法で解決できた。 バージョンアップの前後のOpenSSLとcurlのバージョンは以下の通り。
VerUp前 | VerUp後 | |
---|---|---|
OpenSSL | OpenSSL 0.9.8zh 14 Jan 2016 | OpenSSL 1.0.2o 27 Mar 2018 |
curl | curl 7.54.0 (x86_64-apple-darwin16.0) libcurl/7.54.0 SecureTransport zlib/1.2.8 | curl 7.60.0 (x86_64-apple-darwin16.7.0) libcurl/7.60.0 SecureTransport zlib/1.2.8 |
OpenSSLのインストール
以前Homebrewでインストールしていたようなので、再インストールした。
$ brew reinstall openssl ==> Reinstalling openssl ==> Downloading https://homebrew.bintray.com/bottles/openssl-1.0.2o_1.sierra.bottle.tar.gz Already downloaded: /Users/razgriz1/Library/Caches/Homebrew/openssl-1.0.2o_1.sierra.bottle.tar.gz ==> Pouring openssl-1.0.2o_1.sierra.bottle.tar.gz ==> Caveats A CA file has been bootstrapped using certificates from the SystemRoots keychain. To add additional certificates (e.g. the certificates added in the System keychain), place .pem files in /usr/local/etc/openssl/certs and run /usr/local/opt/openssl/bin/c_rehash This formula is keg-only, which means it was not symlinked into /usr/local, because Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries. If you need to have this software first in your PATH run: echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile For compilers to find this software you may need to set: LDFLAGS: -L/usr/local/opt/openssl/lib CPPFLAGS: -I/usr/local/opt/openssl/include For pkg-config to find this software you may need to set: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig ==> Summary 🍺 /usr/local/Cellar/openssl/1.0.2o_1: 1,791 files, 12.3MB
HomebrewでインストールしたOpenSSLは、PATHに設定されていないようなので、インストールコマンドを打った後にした後に表示されるコメントのコマンドを実行し、HomebrewでインストールしたOpenSSLをPATHに通す。
If you need to have this software first in your PATH run: echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile
$ echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile $ openssl version OpenSSL 1.0.2o 27 Mar 2018
OpenSSLのバージョンが1.0.2oになった。
curlの新しいバージョンをインストール
OpenSSL同様にHomebrewでインストールする。
$ brew install curl ==> Downloading https://homebrew.bintray.com/bottles/curl-7.60.0.sierra.bottle.tar.gz ######################################################################## 100.0% ==> Pouring curl-7.60.0.sierra.bottle.tar.gz ==> Caveats This formula is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble. If you need to have this software first in your PATH run: echo 'export PATH="/usr/local/opt/curl/bin:$PATH"' >> ~/.bash_profile For compilers to find this software you may need to set: LDFLAGS: -L/usr/local/opt/curl/lib CPPFLAGS: -I/usr/local/opt/curl/include For pkg-config to find this software you may need to set: PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig ==> Summary 🍺 /usr/local/Cellar/curl/7.60.0: 423 files, 3MB
こちらもインストール直後はPATHが通っていないようなので、OpenSSL同様に、インストール後の標準出力を参考に、インストールしたcurlをPATHに通してやる。
$ echo 'export PATH="/usr/local/opt/curl/bin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile $ curl -V curl 7.60.0 (x86_64-apple-darwin16.7.0) libcurl/7.60.0 SecureTransport zlib/1.2.8 Release-Date: 2018-05-16
rbenvでRubyをインストール
OpenSSL、curlをバージョンアップした後、めでたくrbenvでRuby2.3.0をインストールできた。
$ rbenv install 2.3.0
ruby-build: use openssl from homebrew
Downloading ruby-2.3.0.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.0.tar.bz2
Installing ruby-2.3.0...
ruby-build: use readline from homebrew
Installed ruby-2.3.0 to /Users/razgriz1/.rbenv/versions/2.3.0
npm install -g はやめる
npm install -g はやめる
WebpackやGulp、Angularなど多くのNode.js製のツールを最近のWeb開発ではよく使うが、 それぞれプロジェクトごとに基本的にはバージョンが違う。
にも関わらず、それらのツールの公式サイトには、まずそのツールを使うには、
以下のように-g
を付けてグローバルにインストールしろ、といったインストール方法が多く書かれている。
npm install -g xxxxxx
手っ取り早く使い始める分にはいいかもしれないが、 複数のプロジェクトが存在する開発者のローカル開発環境には、以下の理由から向いていない。
- グローバルにNode.jsのツールをインストールすると、複数のプロジェクトでバージョンを固定できない。
- グローバルにインストールしたNode.jsツールのライブラリー間でバージョンの競合が起こりうる。
- そして、グローバルにインストールしなくてもそのツールは使える。
グローバルにインストールせずにNode.js製のアプリケーションを使う方法
npm scriptを利用することで、グローバルにインストールしなくてもNode.js製のツールを使うことができる。
Webpackを利用する場合の例
(Node.jsがインストールされていて、npmコマンドが使える前提で書く)
もし、プロジェクトのディレクトリにpackage.jsonが存在しない場合、npm init -y
で作成する。
デフォルトのNode.jsプロジェクトとして初期化され、package.jsonが生成される。
Webpackをインストールする
npm install --save-dev webpack
プロジェクトにインストールしたNode.js製のツールは、node_modulesディレクトリ配下にインストールされる。 これらを実行する場合、このようにパスを直接指定しても実行できる。
./node_modules/.bin/webpack
npm scriptを追加する
上記のようにパスを直接指定してもツールの実行はできるが、npm scriptを使ったほうが便利に実行できる。 プロジェクトディレクトリのpackage.jsonのscriptセクションにwebpack実行用のbuildスクリプトを追加する。
{ "name": "webpack-sample", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" // <- これ }, "author": "", "license": "ISC", "devDependencies": { // 割愛 }, "dependencies": { // 割愛 } }
npm scriptでは、プロジェクトにインストールしたNode.js製ツールの実行ファイルのディレクトリ(node_modules/.bin
)にパスが通った状態でツールを実行するコマンドを書ける。
上記のnpm scriptのbuildスクリプトに指定したwebpackコマンドは、実際は./node_modules/.bin/webpack
が実行される。
npm scriptを実行してみる
npm scriptを実行する時はnpm run xxxx
の形式で実行する。
上記のbuildコマンドの場合、npm run build
になる。
実際に実行してみると、webpackコマンドを実行できていることがわかる。
$ npm run build Hash: 40085d111b680e76b184 Version: webpack 3.10.0 Time: 1988ms Asset Size Chunks Chunk Names app.bundle.js 1.48 MB 0 [emitted] [big] app index.html 274 bytes [emitted] [0] ./src/index.js 598 bytes {0} [built] [2] (webpack)/buildin/global.js 509 bytes {0} [built] [3] (webpack)/buildin/module.js 517 bytes {0} [built] [4] ./src/style.css 1.01 kB {0} [built] [5] ./node_modules/css-loader!./src/style.css 233 bytes {0} [built] [9] ./src/print.js 164 bytes {0} [built] + 4 hidden modules Child html-webpack-plugin for "index.html": 1 asset [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 580 bytes {0} [built] [2] (webpack)/buildin/global.js 509 bytes {0} [built] [3] (webpack)/buildin/module.js 517 bytes {0} [built] + 1 hidden module
npm scriptの中には、npm run
とnpmにrunを続けずに、そのまま実行できるものもある。
npm start
やnpm test
がこれに当たる。
(runを省略できるコマンドの詳細はドキュメント)を参照。)
npm run スクリプトにオプションを指定したい場合
例えば、webpack --watch
など、オプションを指定したい場合もある。
この場合、登録したnpm scriptに--
続けてオプションを入力することで実行できる。
npm run build -- --watch > webpack-sample@1.0.0 build /Users/xxxxxx/yyyyyyyyyyy > webpack "--watch" Webpack is watching the files…
よく使うオプションであれば、オプションを指定したnpm scriptを登録するのがいい。
"scripts": { "build": "webpack", "watch": "webpack --watch" }, // 割愛
オプションを指定する場合でもnpm scriptに登録しておけば楽に実行できる。
npm run watch
まとめ
- プロジェクトごとに利用するNode.jsのツールは、グローバルにインストールしなくてもnpm scriptを使うことで利用できる。
- プロジェクトごとにインストールすることで、プロジェクト間のツールのバージョンの競合を避けられる。
- npm scriptで、ツールのオプションを指定した状態で登録できる。
Node.jsの開発環境の構築 - nvmとnodebrew
nvmとnodebrewは どちらも環境にNode.jsのバージョンを指定してインストールし、インストールした複数のNode.jsを切り替えて使うことができる。
機能の違いとしては、nvmはLong Time Supportのバージョンを自動的に選別してくれる機能がある。構成を選ぶ際には参考にできるかも。
nvmのlts機能
$ nvm install 8 --lts # 8のLTS最新版を落としてくる Downloading and installing node v8.9.4...
$ nvm ls-remote --lts # LTS版のみをリストする . . . v6.13.0 (Latest LTS: Boron) v8.9.0 (LTS: Carbon) v8.9.1 (LTS: Carbon) v8.9.2 (LTS: Carbon) v8.9.3 (LTS: Carbon) -> v8.9.4 (Latest LTS: Carbon)
nvm
インストール
$ brew install nvm
Node.jsのバイナリをインストール
$ nvm install 8.3.0 $ nvm use 8.3.0 $ node -v v8.3.0
ソースからのビルド
$ nvm install -s 8.3.0
nodebrew
インストール
$ brew install nodebrew
Node.jsのバイナリをインストール
nodebrew install
するとソースビルドするのでとても時間がかかる。
$ nodebrew install-binary 8.3.0 $ nodebrew use 8.3.0 $ node -v v8.3.0
ソースからのビルド
$ nodebrew install 8.3.0
Node.js、JavaScriptのオブジェクトをJSON形式の文字列にする
ES6のテンプレートリテラルでオブジェクトをデバッグログに出力したい場合、 JSON.stringfyでJSON文字列化する。 console.logなどの出力メソッドに、オブジェクトをそのまま渡すと以下のようなエラーを吐くものがある。
Cannot convert object to primitive value
expressのGetting Startedをしている最中、リクエストボディをデバッグした際に出た。
console.log(`req.body: ${req.body}`); //TypeError: Cannot convert object to primitive value
JSON形式の文字列にしてあげるといい。
console.log(`req.body: ${JSON.stringify(req.body)}`); // {name: 'Tom'}
余談
実際自分で適当にオブジェクトを作って、テンプレートリテラルに渡しても、[object object]
と表示され、Cannot convert object to primitive value
というエラーにはならない。型の違いなのかもしれないが、どちらもtypeofで調べてもobjectとしか表示されないので、いまいち分かりにくい。
const tom = {name: 'Tom'}; console.log(`tom: ${tom}`); // tom: [object Object]