はじめに
こんなpackage.json
があるとして
$ cat package.json
{
"name": "sample",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"gulp-cache": "^0.4.5",
"gulp-debug": "^2.1.2",
"gulp-eslint": "^3.0.1",
"gulp-size": "^2.1.0"
}
}
yarn
もpackage.json
に対応しているため、
npm install
同様(デフォルトでは)node_modules
にモジュールが降ってきます。
# npm の場合
$ npm install
# yarn の場合
$ yarn
# または
$ yarn install
ちなみに上記のpackage.json
は、以下のコマンドで、作成からモジュールのインストールまで行えます。
# package.json の作成
$ yarn init
# パッケージの追加すると、同時に取得される
$ yarn add gulp-cache gulp-debug gulp-eslint gulp-size
yarn add v0.15.1
[1/4] Resolving packages...
npm install
と何が違うの?
yarn.lock
なるファイルが作成されます。
yarn
の場合yarn.lock
が生成されます。
これはnpm
の shrinkwrap に相当する機能で、
これにより依存するモジュールのバージョンを固定することができます。
# 中身はこんな感じ
$ head yarn.lock
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
dependencies:
acorn "^3.0.4"
acorn@^3.0.4:
version "3.3.0"
じゃあ shrinkwrap との違いは何かといえば
- デフォルトで生成されるので簡単に利用できる
- 各モジュールがソートされており構成管理が容易
確かに人が見てもnpm-shrinkwrap.json
と比べて記載が非常に分かりやすいです。
Yarn: A new package manager for JavaScript
モジュールのフォルダ構造が変わります。(追記あり)
node_modules
の中身を見れば一目瞭然
# npm(v2) の場合
$ ls node_modules/
gulp-cache/ gulp-debug/ gulp-eslint/ gulp-size/
# yarn の場合
$ ls node_modules/
acorn/ generate-object-property/ normalize-package-data/
acorn-jsx/ get-stdin/ number-is-nan/
ajv/ glob/ object.omit/
ajv-keywords/ globals/ object.pick/
ansi-escapes/ globby/ object-assign/
ansi-regex/ glogg/ once/
..... 略
yarn
は依存モジュールも含めてnode_modules
直下に入るためフォルダの数が多くなります。
でもファイルサイズはyarn
の方が小さいです。
# npm(v2) の場合
$ du -sh node_modules/
32M node_modules/
# yarn の場合
$ du -sh node_modules/
20M node_modules/
これは依存により重複しているモジュール、
例えばreadable-stream
の場合だと、以下のように配置されていました。
# npm(v2) の場合
$ find -type d | grep -e readable-stream$
./node_modules/gulp-cache/node_modules/gulp-util/node_modules/multipipe/node_modules/duplexer2/node_modules/readable-stream
./node_modules/gulp-cache/node_modules/gulp-util/node_modules/through2/node_modules/readable-stream
./node_modules/gulp-cache/node_modules/readable-stream
./node_modules/gulp-debug/node_modules/gulp-util/node_modules/multipipe/node_modules/duplexer2/node_modules/readable-stream
./node_modules/gulp-debug/node_modules/through2/node_modules/readable-stream
./node_modules/gulp-eslint/node_modules/bufferstreams/node_modules/readable-stream
./node_modules/gulp-eslint/node_modules/eslint/node_modules/concat-stream/node_modules/readable-stream
./node_modules/gulp-eslint/node_modules/gulp-util/node_modules/multipipe/node_modules/duplexer2/node_modules/readable-stream
./node_modules/gulp-eslint/node_modules/gulp-util/node_modules/through2/node_modules/readable-stream
./node_modules/gulp-size/node_modules/gulp-util/node_modules/multipipe/node_modules/duplexer2/node_modules/readable-stream
./node_modules/gulp-size/node_modules/through2/node_modules/readable-stream
# yarn の場合
$ find -type d | grep -e readable-stream$
./node_modules/concat-stream/node_modules/readable-stream
./node_modules/duplexer2/node_modules/readable-stream
./node_modules/readable-stream
./node_modules/through2/node_modules/readable-stream
npm
で重複されていたモジュールがyarn
ではきれいに整理されています。
ちなみにそれぞれ以下のバージョンのモジュールがインストールされてました。
module | version |
---|---|
./node_modules/concat-stream/node_modules/readable-stream | 2.0.6 |
./node_modules/duplexer2/node_modules/readable-stream | 1.1.14 |
./node_modules/readable-stream | 2.1.5 |
./node_modules/through2/node_modules/readable-stream | 2.0.6 |
この中で最新の(v2.1.5)だけを利用しても問題なさそうな場合は--flat
をつけて実行します。
すると以下のようにどのバージョンのモジュールを使用するかを選択できます。
$ yarn --flat
info Unable to find a suitable version for "readable-stream", please choose one by typing one of the numbers below:
1) "readable-stream@^2.0.4, readable-stream@^2.0.2" which resolved to "2.1.5"
2) "readable-stream@~2.0.0" which resolved to "2.0.6"
3) "readable-stream@~1.1.9" which resolved to "1.1.14"
Answer?:
選択したバージョンがpackage.json
にresolutions
として勝手に記録されました。
$ cat package.json
{
"name": "sample",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"gulp-cache": "^0.4.5",
"gulp-debug": "^2.1.2",
"gulp-eslint": "^3.0.1",
"gulp-size": "^2.1.0"
},
"resolutions": {
"object-assign": "4.1.0",
"readable-stream": "2.1.5",
"vinyl": "1.2.0",
"minimist": "1.2.0",
"strip-bom": "3.0.0",
"estraverse": "4.2.0",
"acorn": "4.0.3"
}
}
# この package.json の状態でインストール
$ yarn
これにより構造はさらにシンプル(1階層のみ)になり、フォルダサイズもちょっと小さくなりました。
$ find -type d | grep -e readable-stream$
./node_modules/readable-stream
$ du -sh node_modules/
19M node_modules/
ただしこの場合、
バージョン指定と異なるモジュールの影響で正しく動作しない可能性があるので注意。
追記
フォルダ構成の違いは、利用しているnpm
のバージョンがv2であることが原因でした。
v3を利用した場合は yarn
とほぼ同じフォルダ構成が得られました。
$ npm -v
3.10.9
$ npm install
$ find -type d | grep -e readable-stream$
./node_modules/concat-stream/node_modules/readable-stream
./node_modules/duplexer2/node_modules/readable-stream
./node_modules/readable-stream
./node_modules/through2/node_modules/readable-stream
このあたり、リンク先の説明が非常に分かりやすかったです。
npm v3 Dependency Resolution
ただ私の環境ではフォルダ構成は完全に一致せず、
一部のモジュールで違いがあり、やはりyarn
のほうが若干シンプルな構造になっているようでした。
# npm(v3.10.3)の場合
$ npm cache clean
$ npm install
$ find -type d | grep -e /isarray$
./node_modules/concat-stream/node_modules/isarray
./node_modules/doctrine/node_modules/isarray
./node_modules/isarray
./node_modules/isobject/node_modules/isarray
./node_modules/readable-stream/node_modules/isarray
./node_modules/through2/node_modules/isarray
$ du -sh node_modules/
21M node_modules/
# yarn(v0.15.1)の場合
$ yarn -v
$ yarn cache clean
$ yarn install
# やはり yarn のほうがよりシンプルな構造になっている
$ find -type d | grep -e /isarray$
./node_modules/duplexer2/node_modules/isarray
./node_modules/isarray
$ du -sh node_modules/
20M node_modules/
コメントの指摘を受け、追記させてもらいました。
まとめ
結局使えるのか?
自分のプロジェクトに適用した場合、npm
に比べてモジュールのインストールがかなり早かったです。
node_modules
のファイルサイズも小さくなってまして、いつでもnpm
に戻れるのでとりあえず使ってみようかなと。
方式 | サイズ |
---|---|
npm install(v2) | 378M |
npm install(v3) | 248M |
yarn install | 237M |
yarn install --flat | 170M |
そもそも利用モジュールを減らしたい...
上記の違い以外にも、オフラインモードやネットワークのパフォーマンス改善など、
そのあたり詳しくはやっぱり公式サイトをどうぞ。