なぜ書くのか?
先日、railsのViewで謎のpadding-top:60px;
に出くわした。検証ツールでみるに、reboot.css
の46行目と書いているが、reboot.css
の中をみてもない。自分のファイルにもそんな記述はない。どうして?色々模索し、先輩エンジニアさんに質問させていただいたところ、以前のscssファイルに書いたpadding-top:60px;
が残り、使われていることがわかった。つまり、現在の最新の状態のscssが読み込まれていなかったそう。どうして、読み込まれていなかったのか?それは、どうやら問題はwebpackにあるようである。
Webpackとは?
Webアプリケーションの装飾に必要なCSS、JavaScript、画像などを1つのファイルとしてまとめるためのモジュールバンドラーで、node.jsのモジュールの1つ。従来、使用するjavascriptファイルを個別で指定していために、表示に時間がかかったり、ファイルの指定を手動で行うために、ミスが発生しやすかった。その問題を解決したのがWebpack。対象のファイルを自動で検出し追加してくれるため、手動によるミスの発生や不適切な順序でファイルが実行されてしまう心配がなくなり、また、時間の高速化にもつながった。
Webpackerとは
WebpackerとはWebpackをRuby on Railsで使うためのgemパッケージ。webpackを良い感じに動かしてくれる優れもの。
Webpackメリットを整理
依存関係のあるJavaScriptのモジュールを解決
ファイル間の依存関係を解析して1つのファイルにまとめてくれるので、保守性が高くなり他のプロジェクトにもファイルを転用しやすくなる。
ファイル読み込みが効率化
ブラウザとウェブサーバーの同時接続数が限られるため、複数のファイルがあると転送に時間がかかる。ファイルを一つにまとめることで、リクエスト回数を減らすことができ、サーバーの負担が少なくなり高速化することができる。
CSSや画像をJavaScriptで扱う
ローダを使えば、HTMLやCSSファイルなど、JavaScript以外のファイルをJavaScriptで扱うことができます。また、画像をDataURLに変換処理したり、コードをチェックしたりすることもできる。
http2とwebpackの関係
HTTP/1.1では同一のホスト名に対して同時にリクエストできる数には制限があるために、複数のスクリプトファイルをwebpackやBrowserifyといったバンドルツールを用いて結合させるのが一般的だった。HTTP/2ではリクエストとレスポンスのストリームが多重化されている。並列して複数のリクエストを送信できるようになったため、これまで当たり前のことであったスクリプトファイルの結合の必要性は薄くなった。しかしながら、http2に置いても二つの点からwebpackを使用するメリットがある
ストリーム数には制限がある
ほとんどのサーバーでは、接続時に送信されるSETTINGSフレームの中で、同時ストリーム数を100などの妥当な値に制限している。これは、100以上の同時リクエストを発行できないことを意味しており、例えば、数百のjsファイルを持つ大規模なアンバンドルReactアプリを持っている場合には問題となる
js間の依存関係をバンドルする
javascript ファイル間には推移的な依存関係があり、http2のようにすべての依存関係をバンドルしていない場合、ブラウザは以前のレスポンスを受信したときにのみ依存関係を発見するため、多くのリクエストラウンドトリップが必要となる。
これらの理由から、webpack を使用していくつかの同種のバンドルをパッケージ化し、最大同時リクエスト数がサーバーの制限を超えないようにする一方で、効率的なブラウザキャッシングを活用するためにバンドルの粒度を十分に保つ。
参考記事
webpackerをRailsアプリケーションに導入
rails6以降は、標準でwebpackerが導入されているが、それ以前のverの場合の既存のアプリにはbin/rails webpacker:install
を使用する。またwebpackerは、yarnに依存するために、yarnを事前にインストールする。Webpackerをインストールすると、デフォルトではapp/javascripts/packs
ディレクトリ以下のJavaScriptファイルがコンパイルされて独自のpackファイルにまとめられる。
例えば私の場合、app/javascript/packs/application.js
というファイルができ、Webpackerはapplicationという名前のpackを作成する。そしてこのpackは、<%= javascript_pack_tag "application" %>
というERBコードで指定し使用する。またすべてのERBで、webpackerの機能を使いたいので、application.html.erb
の headタグ内に記載する。
CSSや画像の場合
What | Webpacker |
---|---|
JavaScriptをアタッチする | javascript_pack_tag |
CSSをアタッチする | stylesheet_pack_tag |
画像にリンクする | image_pack_tag |
css フレームワークを使う
1. application.html.erbの headタグ内に、<%= stylesheet_pack_tag "application" %>、を追加
2. yarn add <フレームワーク名>
railsアプリケーションにbooststrapを導入
-
yarn add jquery bootstrap popper.js
-
必要なモジュールを、グローバル変数に代入する
// jQueryとBootstapのJSを使えるように
const webpack = require('webpack')
environment.plugins.prepend(
'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: 'popper.js'
})
)
- bootstrapをimport
@import '~bootstrap/scss/bootstrap';
import 'bootstrap'
とせずに、必要に応じて個別にプラグインをインポートすることで、無駄を削除
4.bootstrapと、application.scssをimport
import 'bootstrap';
import '../stylesheets/application';
webpackのエントリーファイルだけを置く
ここで重要なのが、app/javascript/packs
ディレクトリにはwebpackのエントリーファイルだけを置き、それ以外のものを置かないことが重要。application.*だけ
app/javascript:
├── packs:
│ # ここにはwebpackエントリーファイルだけを置くこと
│ └── application.js
│ └── application.css
└── src:
│ └──〇〇.js
└── stylesheets:
│ └── ▲▲.css
└── images:
└── ■■.png
構成を変更したい場合
構成を変更したい場合は、config/webpacker.ymlを書き換える。config/webpacker.ymlには、エントリーポイントやdevelopやproduction固有の設定を定義している。
default: &default
source_path: app/javascript # pathを書き換える、以下も同様に
source_entry_path: packs
public_root_path: public
public_output_path: packs
cache_path: tmp/cache/webpacker
webpack_compile_output: true
...続く
ビルドしてみる
bin/webpack
を実行
% bin/webpack
Hash: 5e57f23ab887a258f576
Version: webpack 4.46.0
Time: 5572ms
Built at: 2021-05-01 17:17:56
Asset Size Chunks Chunk Names
js/application-7cad38888ab4f4a77a4e.js 1.27 MiB application [emitted] [immutable] application
js/application-7cad38888ab4f4a77a4e.js.map 1.39 MiB application [emitted] [dev] application
manifest.json 364 bytes [emitted]
app/javascript/packs/application.jsがビルドされて public/packs/ に application.jsとapplication.js.mapというファイルが生成される
.mapて?
.map拡張子はSourceMapといい、コンパイル前とコンパイル後の対応関係を記したファイルである。Json形式で記述されている。ブラウザーが元のソースを再構成して、そのソースをデバッガーに提供することで、デバックをしやすくするらしい。
bin/webpack
でビルドしたjsをインクルードするために、javascript_pack_tag
を使用する。これで、なんとなく流れは理解。
さらに便利にビルドする
bin/webpack-dev-server
このコマンドとrails s
をしてサーバーを動かすと、JS側の変更をホットリロードしてくれるので開発が快適に!下記のようになるので、成功したかもわかりやすい。
<中略>
ℹ 「wdm」: Compiling...
ℹ 「wdm」: Compiled successfully.
# :を抜いた
ERROR
>> padding-top 60px;
----^
最後に
padding-top: 60px;
を消したい!という気持ちから、多くのことを学べた。今までの自分なら、絶対に padding-top: 0px !important;
などと書いたり、あるいは無視したりしていた。近道をしていたら必ずまた同じ問題に遭遇し、その度適当にこなしていたら、どんどん複雑で無駄の多い汚いコードになる。中々課題の進捗はないが、今日もまた昨日より新しい知識を手に入れた。着実に確実に積み上げていきたい。