Yarnやっていきはじめ



## Yarnとは
[Yarn](https://yarnpkg.com/)は **Fast** で **Reliable** で **Secure** なパッケージマネジメントシステムです。
Facebook製でnpm互換があり、npmよりも高速だと話題です。
[rails/webpacker](https://github.com/rails/webpacker)などもYarnを採用しており、これから色々な環境で使われていくのではないでしょうか。
そんなYarnを導入してみたので、その手順を書きます。


## 実際に速いのか

速かったです。下記が実際に現在のプロジェクトでベンチマークをとってみた結果です。
※ キャッシュと`/node_modules`は削除しています。

| コマンド | 計測時間（5回平均） |
|:--|:--:|
|$ time npm install | 44.92s |
|$ time yarn install | 22.10s |
|$ time yarn install --prefer-offline | 16.81s |

[@pine613](http://qiita.com/pine613)さんがGitHub Star上位100を対象にベンチマークを出している資料があります。依存数が多くなればなるほど、速くなり、Yarnの方が遅いパターンは存在しないとのことです。この発表を聞いて、導入してみようと思いました。

[yarn VS. npm@2 VS. npm@3 // Speaker Deck](https://speakerdeck.com/pine613/yarn-vs-npm-at-2-vs-npm-at-3)


## Yarnの導入
[公式のInstallation](https://yarnpkg.com/en/docs/install)に従ってインストールを進めます。Macの場合は、下記、2コマンドで済みます。

```console:console
$ brew update
$ brew install yarn
```

`.zshrc`にPATHを追加。

```Bash:.zshrc
export PATH="$PATH:`yarn global bin`"
```

上記でyarnコマンドが実行できるように🎉

```console:console
$ yarn --version
0.19.1

$ yarn
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
✨  Done in 18.95s.
```

よく使うnpmコマンドとyarnコマンドの置き換えはこちら

| npm | yarn |
|:--|:--|
|$ npm init |$ yarn init |
|$ npm install -S PACKAGE |$ yarn add PACKAGE |
|$ npm install -D PACKAGE |$ yarn add -D PACKAGE |
|$ npm uninstall PACKAGE |$ yarn remove PACKAGE |
|$ npm install |$ yarn |

ちなみに`$ npm prune`コマンドの代替はなく、

```console:console
$ yarn prune

yarn prune v0.19.1
error The prune command isn't necessary. `yarn install` will prune extraneous packages.
info Visit https://yarnpkg.com/en/docs/cli/prune for documentation about this command.
```

とのこと。賢いですね🙆

## Yarnの運用
上述の通り、npmコマンドの箇所はyarnで置き換え可能なので、プロジェクトでnpmを使っていた箇所を置き換えていきましょう。この辺はプロジェクトで利用している技術次第なので、一例として、参考にしてください。Rails + Reactで開発していて、インフラ構築にAnsible、デプロイにCapistranoを利用しています。

```diff:package.json
- "build": "npm run clean && npm run webpack",
+ "build": "yarn run clean && yarn run webpack",
```

```diff:Procfile
- webpack: npm run dev
+ webpack: yarn run dev
  rails: bundle exec rails server -p 3000
```

READMEに記述がある場合は変更しておきましょう。
続いて、デプロイ周り。

```diff:playbook.yml
- - yum: name=npm
+ - get_url: url=https://dl.yarnpkg.com/rpm/yarn.repo dest=/etc/yum.repos.d/yarn.repo
+   become: yes
+ - yum: name=yarn
```

```diff:Capfile
- require "capistrano/npm"
+ require "capistrano/yarn"
```

```diff:Gemfile
  # capistrano
  gem 'capistrano'
  gem 'capistrano-bundler'
- gem 'capistrano-npm'
  gem 'capistrano-rails'
  gem 'capistrano-rbenv'
+ gem 'capistrano-yarn'
  gem 'capistrano3-puma'
```

```diff:config/deploy.rb
- # npm
- set :npm_flags, "--production --silent --no-progress"
- set :npm_roles, :web
- set :npm_env_variables, fetch(:npm_env_variables, {})
+ # yarn
+ set :yarn_flags, "--prefer-offline --production --no-progress"
+ set :yarn_roles, :web
+ set :yarn_env_variables, fetch(:yarn_env_variables, {})

- namespace :npm do
+ namespace :yarn do
    task :build do
-     on roles fetch(:npm_roles) do
-       within fetch(:npm_target_path, release_path) do
-         with fetch(:npm_env_variables, {}) do
-           execute :npm, "run build"
+     on roles fetch(:yarn_roles) do
+       within fetch(:yarn_target_path, release_path) do
+         with fetch(:yarn_env_variables, {}) do
+           execute :yarn, "run build"
          end
        end
      end
    end
  end

- before "npm:install", "npm:prune"
- after "npm:install", "npm:build"
+ after "yarn:install", "yarn:build"
```

最後にCircleCI。

```yml:circle.yml
machine:
  timezone:
    Asia/Tokyo
  environment:
    YARN_VERSION: 0.19.1
  ruby:
    version: 2.3.1
  node:
    version: 6.9.1
  post:
    - if [[ $(yarn --version 2>/dev/null) != "${YARN_VERSION}" ]]; then curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version $YARN_VERSION; fi
dependencies:
  cache_directories:
    - "~/.cache/yarn"
  override:
    - yarn install --prefer-offline
    - bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
test:
  override:
    - yarn run test
    - bundle exec rspec --color --require spec_helper spec --format progress
    - bundle exec rubocop
```

## まとめ
上述の通り、テストやデプロイにかかる時間を短縮できるメリットがあり、簡単に置き換え可能なので、Yarnを導入してみてはいかがでしょうか。

## 参考
[Yarn](https://yarnpkg.com/)
[yarn VS. npm@2 VS. npm@3 // Speaker Deck](https://speakerdeck.com/pine613/yarn-vs-npm-at-2-vs-npm-at-3)
[amakanでyarnを使うようにした - ✘╹◡╹✘](http://r7kamura.hatenablog.com/entry/2016/12/08/061203)