Help us understand the problem. What is going on with this article?

yarnがnpmと何が違うのか試してみた

More than 3 years have passed since last update.

はじめに

こんな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"
  }
}

yarnpackage.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.jsonresolutionsとして勝手に記録されました。

$ 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

そもそも利用モジュールを減らしたい...

上記の違い以外にも、オフラインモードやネットワークのパフォーマンス改善など、
そのあたり詳しくはやっぱり公式サイトをどうぞ。

0829
データ駆動はじめました
https://dd1.work/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした