Ruby・Node.js・Goのライブラリバージョン管理比較


## 対応表

|  | Ruby | Node.js | Go |
|:-:|:-:|:-:|:-:|
| 言語バージョン管理ツール  | rvm, rbenv<br><br><例><br>rbenv install 3.0.0 && rbenv local 3.0.0 #=> 3.0.0 (set by /Users/yokoto/.rbenv/version)| nvm, nodenv, n<br><br><例><br>nvm install 19.2.0 && nvm use 19.2.0 #=> Now using node v19.2.0 (npm v8.19.3)  |  go, goenv<br><br><例><br>go install golang.org/dl/go1.18.8 && go1.18.8 download #=> go version go1.18.8 darwin/arm64 |
|レジストリ（パッケージ管理システム）|RubyGems<br>https://rubygems.org| npm（Node Package Manager）<br>https://www.npmjs.com| go<br>https://pkg.go.dev|
| パッケージ依存関係管理クライアント  |  gem, [Bundler](https://bundler.io/)<br><br><例><br>gem install bundler && bundler -v  #=> Bundler version 2.3.26| npm, yarn<br><br><例><br>## npm<br>npm install -g npm && npm version #=> { npm: '8.19.3', node: '19.2.0',  ...,}<br><br>## yarn<br>npm install -g yarn && yarn version #=> 3.2.0 |  GOPATH, Go Modules<br><br><例><br>go version #=> go version go1.18.8 darwin/arm64  |
| パッケージバージョン・依存関係管理ファイル  | Gemfile<br>Gemfile.lock<br><br><例><br>bundle init && Gemfileの書き換え && bundle install  | ## npm<br>package.json<br> package-lock.json<br><br><例><br>npm init && package.jsonの書き換え && npm install<br><br><br>## yarn<br>package.json<br>yarn.lock<br><br><例><br>yarn init && package.jsonの書き換え && yarn install  | go.mod<br>go.sum<br><br><例><br>go mod init yokoto/go-mod-demo && go.modの書き換え && go mod tidy  |
| 特定パッケージの依存関係確認方法 | ・ [RubyGems.orgの特定のgemのページ](https://rubygems.org/gems/nokogiri/versions/1.15.2/dependencies)<br>Gemfile.lockを確認する<br>・gem dependency -R nokogiri | ## npm<br>・package-lock.jsonを確認する<br>・npm ls react<br>・npm view react dependencies<br><br>## yarn<br>・yarn.lockを確認する<br>・yarn list react<br>・yarn info react dependencies | ・go.modファイルを確認する<br>・go list<br>・go mod graph
|パッケージのインストール先ディレクトリ | app_root/.bundle/ruby/2.7.0/gems（デフォルト）, app_root/vendor/bundle/ruby/3.0.0/gems/（よくある） | app_root/node_modules/ | \\$GOPATH/bin, \\$HOME/go/bin
| 特定パッケージの最新バージョンへのアップデートコマンド  | bundle update nokogiri --conservative  | ## npm<br>npm uninstall react && npm install react<br><br>## yarn<br>yarn remove react && yarn add react | go get gopkg.in/yaml.v3 && go mod tidy  |

## Ruby
### ポイント

- `require: false`
    - Bundlerはconfig/application.rbにある `Bundler.require(*Rails.groups)` という記述によって、Gemfile内のgemを `require` （= 各ファイルにライブラリをロード）するが、 `require: false` を指定することでgemをインストールする一方 `require` しないようにする。
    - たとえば、コマンドラインから実行するrubocop等のgemはRailsアプリケーションのプロセスで読み込む必要がないし、 `rake` タスクでのみ使用するgemはそのタスク内でのみgemを `require` するようにした方がメモリ効率が良い。

https://bundler.io/docs.html

https://techracho.bpsinc.jp/hachi8833/2022_11_10/121901

https://stackoverflow.com/questions/4800721/ruby-what-does-require-false-in-gemfile-mean#comment15942297_4800746

https://masuyama13.hatenablog.com/entry/2021/01/10/225038

https://teratail.com/questions/88151

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/require.html

https://blog.wyrd.co.jp/2022/04/01/%E3%81%AA%E3%81%9Cruby-on-rails%E3%81%A7%E3%81%AFrequire%E3%82%92%E5%AE%9F%E6%96%BD%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%88%E3%81%84%E3%81%AE%E3%81%8B/

- `group: :production, :development, :test do ~ end`
    - `group` で指定した環境のみにgemをインストールすることができる。

https://neko314.hatenablog.com/entry/2020/11/21/231326

https://pikawaka.com/rails/env

https://ja.stackoverflow.com/questions/77753/development-%E4%BB%A5%E5%A4%96%E3%81%AB%E3%81%A0%E3%81%91%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%9F%E3%81%84-gemfile-%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9

- `bundle install` vs `bundle install --path vendor/bundle` vs `bundle update`
    - `bundle install`
        - Gemfile.lockがあれば、Gemfile.lockの内容に基づいてgemをインストールする。
        - Gemfile.lockがなければ、Gemfileを元にGemfile.lockを作成し、gemをインストールする。
        - `--path` や `BUNDLE_PATH` の指定がない場合、gemをグローバル（システム）にインストールする。
            - `gem environment` や `bundle config` によってgemのインストール先を確認できる。
    - `bundle install --path vendor/bundle`
        - gemを `vendor/bundle` ディレクトリ配下にインストールする。
    - `bundle update`
        - Gemfileの内容に基づいてGemfile.lockを更新する。

https://qiita.com/dawn_628/items/1821d4eef22b9f45eea8

https://k-koh.hatenablog.com/entry/2020/01/15/100536

https://teratail.com/questions/94285

https://qiita.com/lasershow/items/1a048d03ddaaba98171e

https://qiita.com/jnchito/items/99b1dbea1767a5095d85

https://qiita.com/okuramasafumi/items/1aea3ed27763315328a3

https://qiita.com/devzooiiooz/items/8babd82f780f01812f9d

- `bin` vs `bundle exec`
    - `bin`
        - 実行可能ファイル（バイナリ）が入っているディレクトリ。
        - `binstub` というスクリプトによってラップされて実行される。
        - `bin` を使うとSpringを起動でき、結果としてコマンドの実行が高速になる。
    - `bundle exec`
        - `bundle exec` をつけると現在のプロジェクトでインストールされたgemを使用してコマンドを実行する。
        - つけないと、システム共通のgemを使用してコマンドを実行する。
        - `bundle binstubs（bundle install --binstubs）` を実行し、指定したgemのbinstubsを作成すれば、`bundle exec` を打たずに `bin` を付けるだけでコマンド実行することができる。例） `./bin/rspec`, `./bin/rake`

https://qiita.com/NasuPanda/items/975328eddf4ea22465f8

https://techracho.bpsinc.jp/hachi8833/2021_11_22/25037

https://qiita.com/tanaka51/items/bc22c1c364202d3cce4e

https://qiita.com/jnchito/items/c5a0848144203dce6e26

https://o-kay796.hatenablog.com/entry/2021/07/18/081826

https://qiita.com/d0ne1s/items/fa2dafcee02e963fe997

### Gemfile

```rb
source 'https://rubygems.org'

gem 'nokogiri'
```

### Gemfile.lock

```
GEM
  remote: https://rubygems.org/
  specs:
    nokogiri (1.13.9-x86_64-darwin)
      racc (~> 1.4)
    racc (1.6.0)

PLATFORMS
  x86_64-darwin-19

DEPENDENCIES
  nokogiri

BUNDLED WITH
   2.3.26
```

## Node.js
### ポイント

- `npm install` vs `npm install -g [package]` vs `npm install [package] (-S(--save) / -P(--save-prod))` vs `npm install [package] -D(--save-dev)`
    - `npm install`
        - package-lock.jsonがあれば、package.json と package-lock.json に基づいて `dependencies` と `devDependencies` がすべてローカル（node_modules）にインストールされる。
        - package-lock.jsonがなければ、package.json を元にpackge-lock.jsonを作成し、`dependencies` と `devDependencies` がすべてローカル（node_modules）にインストールされる。
    - `npm install --production`
        - package.jsonの `dependencies` に記述されたパッケージだけがnode_modulesにインストールされる。
        - Rubyの `bundle install` に相当する。
    - `npm install -g [package]`
        - パッケージはグローバルに（プロジェクトの外側のユーザー単位で）インストールされる。
        - package.jsonには記述されない。
            - 例: `npm install -g yarn`
        - Rubyの `gem install [package]` に相当する。
    - `npm install [package] (-S(--save) / -P(--save-prod))`
        - package.jsonの `dependencies` に記述する。
        - package.jsonの `dependencies` に記述されたパッケージは本番環境で使用することができる。
            - 例: react、vue
    - `npm install [package] -D(--save-dev)`
        - package.jsonの `devDependencies` に記述する。
        - package.jsonの `devDependencies` に記述されたパッケージは開発時のみに使用することができる。
            - 例: jest、eslint、webpack、typescript
- Semantic Versioning 
    - Major・Minor・Patch

https://qiita.com/righteous/items/e5448cb2e7e11ab7d477

https://yayoi.tech/entry/difference_between_dependencies_and_devDependencies

https://qiita.com/chihiro/items/ca1529f9b3d016af53ec

http://var.blog.jp/archives/76748158.html

https://the2g.com/post/difference-between-npm-install

https://qiita.com/0x50/items/980505fabc91f6ed95e5

### package.json

```package.json
{
  "name": "node-js-demo",
  "version": "1.0.0",
  "description": "first node js project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "yokoto",
  "license": "ISC",
  "dependencies": {
    "react": "^18.2.0"
  }
}
```

### package-lock.json


```package-lock.json
{
  "name": "node-js-demo",
  "version": "1.0.0",
  "lockfileVersion": 2,
  "requires": true,
  "packages": {
    "": {
      "name": "node-js-demo",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "react": "^18.2.0"
      }
    },
    "node_modules/js-tokens": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
    },
    "node_modules/loose-envify": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
      "dependencies": {
        "js-tokens": "^3.0.0 || ^4.0.0"
      },
      "bin": {
        "loose-envify": "cli.js"
      }
    },
    "node_modules/react": {
      "version": "18.2.0",
      "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
      "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
      "dependencies": {
        "loose-envify": "^1.1.0"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    }
  },
  "dependencies": {
    "js-tokens": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
    },
    "loose-envify": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
      "requires": {
        "js-tokens": "^3.0.0 || ^4.0.0"
      }
    },
    "react": {
      "version": "18.2.0",
      "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
      "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
      "requires": {
        "loose-envify": "^1.1.0"
      }
    }
  }
}
```


## Go

### ポイント

- 〇〇env
    - 複数バージョンの処理系を混在させるために、Rubyでは rbenv、Node.jsではnodenv などのツールが普及しており、Goでも [goenv](https://github.com/syndbg/goenv) のようなツールがある。
       - しかし、Goには [v1 系に関しては後方互換性が保たれる](https://golang.org/doc/go1compat)ため、（常にバージョンアップできていれば）プロジェクトごとにバージョンを固定する必要はない。
       - また、Goには公式で[複数バージョンを混在させる方法](https://golang.org/doc/manage-install#installing-multiple)が提供されている。

https://tenntenn.dev/ja/posts/2021-06-27-xxenv

https://shinshin86.hateblo.jp/entry/2021/11/20/111636

https://stackoverflow.com/questions/42186003/how-to-uninstall-go

- `GOPATH` vs GoModules
    - ~v1.10
        - `GOPATH` を使用してライブラリのパッケージ管理が行われていた。
            - 環境変数 `GOPATH` で指定されたディレクトリの配下でソースコードを管理する必要があった。
    - v1.11~
        - Go Modules（go.mod・go.sum）というツールチェーンを使用してライブラリのモジュール管理が行われるようになった。
            - 標準ライブラリを除く全てのパッケージをモジュールとして管理できるようになった（npmなどと同様の方法）。
    - ~v1.15
        - `go build` や `go test` といったコマンドの実行時に go.mod および go.sum ファイルが更新されていた。
    - v1.16~
        - `go mod tidy` を実行すると go.mod および go.sum ファイルが更新されるようになった。

https://dev.classmethod.jp/articles/go-setup-and-sample/

https://www.st-hakky-blog.com/entry/2020/06/09/092312

https://zenn.dev/spiegel/articles/20210223-go-module-aware-mode

https://poyo.hatenablog.jp/entry/2021/12/11/123810

https://blog.framinal.life/entry/2021/04/11/013819

https://zenn.dev/optimisuke/articles/105feac3f8e726830f8c

- `go install` vs `go get`
    - `go install`
        - Go 1.16以降では、バイナリをビルドしてグローバルインストールのためのコマンドとして利用される。
            - ビルドされた実行可能なバイナリは、グローバル（`$GOPATH/bin` ディレクトリ）にインストールされる。
            - バージョンも指定してパッケージをダウンロードすることが可能になった。
                - 例: `go install golang.org/x/tools/gopls@latest`
    - `go get`
        - Go 1.16以降では、go.mod を編集するためだけのコマンドとして利用される。
        1. コードにimport文を書いてから go.mod に反映する方法
            - `go get` && `go mod tidy`
        2. importされていないモジュールを go.mod に追加する方法
            - `go get <package>[@<version>] # 実行後、手作業で go.mod　を編集する`

https://qiita.com/eihigh/items/9fe52804610a8c4b7e41

### main.go

```go
package main

import (
	"fmt"

	"rsc.io/quote"
)

func main() {
	fmt.Println(quote.Go())
}
```

### go.mod

```go
module yokot/go-mod-demo

go 1.18

require rsc.io/quote v1.5.2

require (
	golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
	rsc.io/sampler v1.3.0 // indirect
)
```

### go.sum

```go
module yokot/go-mod-demo

go 1.18

require rsc.io/quote v1.5.2

require (
	golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
	rsc.io/sampler v1.3.0 // indirect
)
```