Webpackerを使いこなしたい今日この頃の俺だ。

# まず、Webpackとは
[webpack](https://webpack.js.org/)とは、簡単に言うと、`「JavaScript」「CSS」「画像やフォント」といった静的アセット(JavaScriptモジュール)を束ねることができるツール`のことです。
私たち開発者にとって使いやすい方法でフロントエンドのコードを書き、そのコードをブラウザで利用しやすい方法でパッケージ化することが目的です。

## Webpackのメリット
- 依存関係のあるJavaScriptモジュールを解決
    - ファイル間の依存関係を解析して1つのファイルにまとめてくれるので、ファイルの依存関係を解決できます。
- 読み込み順を気にする必要が無くなり、リクエストが一度で良くなり効率的
    - リクエスト回数を減らせる(通信回数が減る)ため、サーバーの負担が少なくなります。
- JavaScriptモジュールを簡単にブラウザで扱える形に変換できる
    - WebpackはJavaScriptモジュールを結合する前後にコードの変換処理行う事が可能です。これにより、クライアントサイドの環境に影響されづらく、開発効率も向上します。
- loaderやpluginなどが豊富
    - JSファイルでないものをJSファイルに変換できるloaderや、Webpackを拡張できるpluginが豊富です。
- 様々なフレームワークで採用されているのでライブラリからサンプルを見つけやすい
    - 有名なWebフレームワークでもWebpackが標準で採用されてきているため、サンプルも見つけやすい。

# Webpackerとは
Webpackerは、モダンなフロントエンド開発を強力にサポートするWebpackをRuby on Railsで使うためのgemパッケージのことで、標準的なwebpackの設定と合理的なデフォルト設定を提供します。

## WebpackerとSprocketsの異なる理由
RailsにはSprocketsが同梱されています。Sprocketsとは、アセットパッケージングツールのことで、Webpackerと機能が重複している部分もあります。
SprocketsはRailsで使われる前提で設計されており、統合方法はシンプルで、gemを用いてSprocketsにコードを追加できます。
対してWebpackは、モダンなJavaScriptツールやNPMパッケージとの統合に優れており、より多くのものを統合することができます。WebpackではCSSを管理することもできます。

### Webpackerを利用する方が良い場合
- 新しいプロジェクトで「NPMパッケージを使いたい場合
- 最新のJavaScript機能やツールにアクセスしたい場合

上記の場合は、Webpackerを選択すべきです。

### Sprocketsを利用する方が良い場合
- 移行にコストがかかるレガシーアプリケーション
- gemで統合したい場合
- パッケージ化するコードの量が非常に少ない場合

上記の場合は、Sprocketsを選ぶべきです。

#### [参考]WebpackerとSprocketsの対比表

| タスク | Webpacker | Sprockets |
|:-:|:-:|:-:|
| JavaScriptをアタッチ  | javascript_include_tag  | javascript_pack_tag  |
| CSSをアタッチ  | stylesheet_link_tag  | stylesheet_pack_tag  |
| 画像にリンク  | image_url  | image_pack_tag  |
| アセットにリンク  | asset_url  | asset_pack_tag  |
| スクリプトをrequire  | //= require  | import または require  |

## Webpackerのインストール方法
※Webpackerを使うには、Yarnパッケージマネージャー（1.x以上）とNode.js（10.13.0以上）のインストールが必要です。

＜新規プロジェクト作成時にインストールする＞
`rails new`コマンド実行時にオプションを付与することで、新規プロジェクト作成と同時にインストールしてくれる。

```bash
$ bundle exec rails new sample_app --webpack
```

＜既存のプロジェクトにインストールする＞
以下コマンドを実行する。

```bash
$ rails webpacker:install
```

### Webpackerで追加されたファイル一覧

| 場所 | 説明 |
|:-:|:-:|
| app/javascript  | フロントエンド向けJavaScriptソースコードの置き場所  |
| app/javascript/packs/application.js | デフォルトのエントリーポイント |
| bin/webpack  | webpackでコンパイルを実行  |
| bin/webpack-dev-server  | webpack-dev-serverを実行  |
| config/webpacker.yml  | Webpackerのgemを設定  |
| config/webpack/environment.js  | ローダーやプラグインの設定 ​|
| babel.config.js  | Babel（JavaScriptコンパイラ）の設定  |
| postcss.config.js  | PostCSS（CSSポストプロセッサ）の設定  |
| .browserslistrc  | Browserlist（対象ブラウザを管理する）設定  |
| node_modules/  | node.jsのモジュール群の保管場所  |
| package.json  | node.jsの依存関係を解決  |

### Webpackerでフレームワークを統合
Webpackerには、有名なJavaScriptフレームワークやツールのサポートも多数含まれています。
これらのフレームワークやツールは、新規プロジェクト作成時に`rails new sample_app --webpack=<フレームワーク名>`のような方法で作成するか、`rails webpacker:install:<フレームワーク名>`のように個別のコマンドラインタスクで作成することができます。

#### 主なフレームワーク統合コマンド

| フレームワーク | コマンド | 説明 |
|:-:|:-:|:-:|
| Angular  | rails webpacker:install:angular  | AngularとTypescriptのセットアップ  |
| ERB  | rails webpacker:install:erb  | JavaScriptファイル内でのERBサポートのセットアップ  |
| React  | rails webpacker:install:react  | ReactJSのセットアップ  |
| TypeScript  | rails webpacker:install:typesctipt  | プロジェクトで用いるTypescriptのセットアップ  |
| Vue  | rails webpacker:install:vue  | VueJSのセットアップ  |

## 使い方

### JavaScriptをWebpacker経由で利用する
Webpackerをインストールすると、デフォルトではapp/javascripts/packsディレクトリ配下にのJavaScriptファイルがコンパイルされて独自のpackファイルとしてまとめられます。

たとえば、app/javascript/packs/application.jsというファイルが存在すると、Webpackerは`applicationという名前のpackを作成`します。
このpackは、`<%= javascript_pack_tag "application" %>`というERBコードが使われているRailsアプリケーションで追加されます。これによって、application.jsが変更されるたびに再コンパイルされ、ページを読み込むとコンパイル後のpackが使われます。

```app/javascript/packs/application.js
import 'javascripts/application.js'; // javascripts/application.js配下のファイルをインポート
import 'stylesheets/application.scss';

require.context('images/', true);
```

packを多数作成するとコンパイルのオーバーヘッドが大きくので、`app/javascript/packsディレクトリにはwebpackのエントリーファイルだけを置き、それ以外のものを置かない`ことが重要です。
以下はソースコード構造の例です。

```
app/javascript:
  ├── packs:
  │   # ここにはwebpackエントリーファイルだけを置くこと
  │   └── application.js
  │   └── application.scss
  └── javascripts:
  │   └── sample.js
  └── stylesheets:
  │   └── sample.scss
  └── images:
      └── logo.svg
```

### CSSをWebpacker経由で利用する
Webpackerでは、PostCSSプロセッサを用いてCSSやSCSSのサポートを即座に利用可能です。

CSSコードをpackにインクルードするには、まずCSSファイルをトップレベルのpackファイルにインクルードします。
JavaScriptの時と同様の手順でインポートすることで、webpackがCSSファイルをダウンロードに含められるようになります。

```app/javascript/packs/application.js
import 'javascripts/application.js';
import 'stylesheets/application.scss'; // stylesheets/application.scsss配下のファイルをインポート

require.context('images/', true);
```

実際にWebページで読み込むには、ビューのコードに`<%= stylesheet_pack_tag "application" %>`を追加します。

### 静的アセットをWebpacker経由で利用する
Webpackerのデフォルト設定では、画像やフォントなどの静的アセットもすぐに使用可能です。
この設定では、様々なファイルのフォーマットに対応する拡張子が多数含まれており、webpackはそれらの拡張子も生成されたmanifest.jsonファイルに追加します。

webpackのおかげで、以下のコード例のように静的アセットをJavaScriptファイル内で直接インポートできます。インポートされた値は、そのアセットへのURLを表します。

```
import myImageUrl from '../images/my-image.jpg'

// ...
let myImage = new Image();
myImage.src = myImageUrl;
myImage.alt = "I'm a Webpacker-bundled image";
document.body.appendChild(myImage);
```

Webpackerの静的アセットをRailsのビューで参照するには、WebpackerにバンドルされるJavaScriptファイルで明示的にrequireする必要があります。
`Sprocketsとは異なり、Webpackerはデフォルトでは静的アセットをインポートしない`点にご注意ください。
ディレクトリはapp/javascriptを起点とする相対パスです。テンプレートではimagesというディレクトリ名になっていますが、app/javascriptの中であれば任意のディレクトリ名に変更できます。

```app/javascript/packs/application.js
import 'javascripts/application.js';
import 'stylesheets/application.scss';

require.context("/images", true) // 静的アセットをインポート
```

静的アセットは、`public/packs/mediaディレクトリ以下に出力`されます。
(例)
app/javascript/images/my-image.jpgにある画像をインポート
↓
public/packs/media/images/my-image-abcd1234.jpg

#### ActionViewヘルパーとWebpackerヘルパーの対比表

| ActionViewヘルパー | Webpackerヘルパー |
|:-:|:-:|
| favicon_link_tag  | favicon_pack_tag  |
| image_tag  | image_pack_tag  |

## 環境ごとのWebpacker設定について
Webpackerにはデフォルトで「development」、「test」、「production」の3つの環境があります。`webpacker.yml`ファイルに環境設定を追加することで、環境ごとに異なるデフォルトを設定できます。また、Webpackerは環境設定を追加するためにconfig/webpack/<environment>.js ファイルを読み込みます。

## development環境でWebpackerを実行
Webpackerには、development環境で実行する.`/bin/webpack`と.`/bin/webpack-dev-server`という2つのbinstubファイルが同梱されています。
これらのbinstubファイルは、`環境に応じて適切な設定ファイルや環境変数が読み込まれる`ようになっています。

development環境のWebpackerは、デフォルトでRailsページが読み込まれると`必要に応じて自動的にコンパイル`を行います。つまり別のプロセスの実行は不要であり、コンパイルエラーは標準のRailsログに出力されます。
これを変更するには、`config/webpacker.ymlファイル`を`compile: false`に変更します。
`bin/webpack`を実行すると、packを強制的にコンパイルします。

webpack-dev-serverのプロセスは、`app/javascript/packs/*.jsファイルの変更を監視して変更時に自動的に再コンパイルし、ブラウザを再読み込み`します。

# Yarnを使おう
Yarnとは、2016年にFaceBookが公開したJavaScriptのパッケージマネージャです。
今後は、YarnでJSやCSSのパッケージを管理し、モジュールバンドラをWebpackerで利用するのが主流になるようです。
Yarnは、常に最新のJavaScriptライブラリを提供してくれてかつ自動でバージョン管理も行ってくれます。

## Yarnのメリット
- npmより高速でインストール出来る

- npmより厳密にモジュールのバージョンを固定可能
    - yarn.lockファイルで、各パッケージのインストールバージョンを固定できる。

- npmの同時使用が可能
    - npmと同じでpackage.jsonが使えるため、同一プロジェクトでnpm or yarnで固定する必要が無い。

## Yarnの使い方
### Yarnのインストール
※どちらの方法でも良い。

```bash
$ npm install -g yarn

$ brew install yarn
```

### バージョン確認

```bash
$ yarn -v
```

### package.jsonの生成
※プロジェクトにまだpackage.jsonがない場合に以下のコマンドで生成可能。

```bash
$ yarn init # npm initと同義
```

### yarnでパッケージをインストール

```bash
$ yarn # npm installと同義
```

### パッケージの追加
パッケージのインストールとpackage.jsonへの追加が可能。

```bash
$ yarn add [パッケージ名] # npm install --saveと同義
```

### パッケージのアンインストール

```bash
$ yarn remove # npm uninstallと同義
```

### グローバルインストール

```bash
$ yarn global add [パッケージ名]
```

### すでにインストールされたファイルが削除されていないことを確認

```ruby
$ yarn install --check-files
```

# 終わりに
これで少しだけでもWebpackerに近付けたんでは無いでしょうか？
今後は主流となるであろうgem、Webpackerはいずれ学習しなければならない時が来ると思います。
その時に慌てて学習するのでは無く、今から前もって知識として身に付けておきましょう！！

# 参考
[Webpacker の概要]
(https://railsguides.jp/webpacker.html)

[yarnとは]
(https://qiita.com/akitxxx/items/c97ff951ca31298f3f24)