新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳)

新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳) 新しいRailsフロントエンド開発(2)コンポーネントベースでアプリを書く(翻訳) 新しいRailsフロントエンド開発(3)Webpackの詳細、ActionCableの実装とHerokuへのデプロイ(翻訳) 概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: Evil Front Part 1: Modern Front-end in Rails 原文公開日: 2017/12/05 著者: Andy Barnov、Alexey Plutalov サイト: Evil Martians 新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳) 前書き 本記事は、フロントエンドのフレームワークに依存しないRailsプレゼンテーションロジックを現代的かつモジュール単位かつコンポーネントベースで扱う方法を独断に基いて解説するガイドです。3部構成のチュートリアルで、例を元に最新のフロントエンド技術の最小限に学習し、Railsフロントエンド周りをすべて理解しましょう。 Part 2、Part 3もご覧ください。 混乱しがちな部分 今新たに実地のRailsフルスタック開発者になるということは、混乱の渦中で頑張るということです。Asset Pipeline/Sprockets/CoffeeScript/Sassを用いてフロントエンドを扱う「昔ながらのRails」wayは、2017年ともなると色褪せて見えます。Rails 3.1時代に選択された技術の多くは、現代の想定に応えられていません。昔ながらの手法にこだわり続ければ、この5年間にフロントエンド界隈で起こったあらゆる新技術を見送ることになってしまいます。全てを統べるJavaScriptパッケージマネージャnpmの台頭、頼もしいJavaScript文法であるES6の隆盛、連勝を重ねるBabelトランスパイラやビルドツール、かつてないほど成長を続ける CSSプリプロセッサPostCSS。フロントエンドのコードを「ページ」から「コンポーネント」にパラダイム変換したReactやVueなどのフロントエンドフレームワークが驚異的な成功を収めていることは申し上げるまでもありません。 これほどまでに複雑になったフロントエンド技術を1人の開発者の頭に押し込めようとすれば(キャリアの浅い人はなおさら)、認知機能が悲鳴を上げていわゆるJavaScript疲労になるのがオチです。 しかし、確立されたワークフローに疑問を感じるのは、時代に取り残された気持ちになるからとか、フロントエンド屋との技術トークがどんどん通じなくなるからとか、将来の見通しに不安を感じるからという理由だけではありません。つまるところ、プログラマーとは理性的な人間なのです。 Asset Pipelineの何が問題だったのか 昔ながらの方法が今も使えることについては触れないことにしましょう。今でも、Rails標準のフロントエンド向けセットアップ(とCoffeeScript)を使って成果を出せます。ビューテンプレート、スクリプト、スタイルシートは従来同様Asset Pipelineで結合/最小化されて配信されます。本番環境では2つの(少なくとも人間には)読めないファイルの形を取るので、重要性は変わりません。 しかし、開発者は普通次のような点に心を配っています。 分離され、再利用可能かつテスト可能な、理解しやすいコードであること コードの変更->結果の表示を短いサイクルで繰り返せること 依存関係の管理が面倒でないこと ツールがちゃんとメンテされていること 言うまでもなく、「昔ながらの」Railsは私たちのコードに何らかの構造を与えます。ビューテンプレート、JavaScript、スタイルシート、画像ごとに個別のフォルダが用意されます。しかしフロントエンドが複雑になればなるほど、これらを追っているうちに認知能力が低下(訳注: 参考)してしまいます。 「昔ながらの」フルスタックRails wayをおそろかにすれば、たちまちCSSやJSは死んだコードのグローバルなゴミ捨て場と化してしまうでしょう。 乗り換えを検討する理由の中には「スピード」もあります。Sprocketが遅いという問題については山ほどドキュメントがありますし、Herokuにいたっては、Asset Pipelineのパフォーマンス最適化方法に特化したガイドまで公開しています。そこではRailsアプリのデプロイで最も時間がかかるのがアセットの扱いであることを認めています。曰く「平均すると、依存関係をbundle installでインストールするときよりも20倍以上遅い」。 開発中にCSSを1行変更してページを再読み込みするときも、結果が表示されるまでに多少待たされます。この待ち時間はすぐに長くなります。 依存関係についてはどうでしょうか。Asset Pipelineを常に最新に保つのは大仕事です。プロジェクトにJavaScriptライブラリを1つ追加する場合、CDNから読み込んだコードをコピペしてapp/assetsやlib/assetsやvendor/assetsに置くか、誰かがgem化してくれるまでぼんやり待つ方法があります。その間にも、JavaScriptコミュニティは同じことをnpm installコマンド、今ならyarn addコマンド一発で管理しています。アップデートも同様です。YarnはJavaScriptをBundlerのように便利に扱うことができます。 最後は、Asset Pipelineを支えるビルドツールであるSprocketsです。Sprocketsの最近のメンテ状況ははかばかしくありません。 Sprocketsはかれこれ5年以上ほこりを被ったままです(左)。同じ時期のWebpackは頻繁に更新されています(右)。 風向きが変わった 2017年、DHHとRailsコミュニティはフロント周りの変更に手を付け始めました。Rails 5.1ではwebpacker gemによるWebpack統合、Yarnを介したnode_modules、すぐに使えるBabel/React/Vue/PostCSSが(その気になればElmも)導入されました。 しかしAsset PipelineとCoffeeScriptは今も彼らがメンテしています。rails newだけでプロジェクトを開始すると、昔ながらのRailsになります。JavaScript関連のトピックをググるときには、相変わらずコード例を脳内トランスパイルして隅々まで理解しなければなりません。 くよくよすることはありません。今日のRailsアプリではあらゆる現代的な手法を利用可能です。本シリーズで私たちと一緒に基礎を固めましょう。Rails/JavaScript/CSSの基本的な知識が多少あれば十分始められます。本シリーズでは設定やツールを最小限に抑えるため、最新のRails 5.1以降の機能も積極的に使います。 本チュートリアルのシリーズでは、Evil Martiansで培われた現代的で練り上げられたフロントエンド構築ベストプラクティスの一部を皆さまにご紹介いたします。 心の壁 Reactは私たちにコンポーネントで思考するよう指導します。その他の現代的なフロントエンドフレームワークもこれに準じています。モジュラリティは、BEMをはじめとする主なCSS方法論を支える哲学です。モジュラリティのコンセプトは「UIを構成するあらゆる論理的な部品は自己完結(self-contained)すべきである」というシンプルなものです。 Railsでは、ビューを論理的な部品に分割する方法が組み込まれています(ビューのパーシャル)。しかしパーシャルがJavaScriptに依存すると、おそらく他の現代的なコンポーネントと同様にapp/assets/javascriptsの下にある深いフォルダにアクセスしなければならなくなります。 パーシャルを使うときに一切合財をまとめることができれば、各パーシャルのスクリプトやスタイルシートを1箇所にまとめられるのではないでしょうか? これからご紹介するアプローチは、React/Vue/Elmのアーキテクチャに依存していません。そしてそのように作られています。自分が使うツールの利用法を気兼ねなく学ぶことができますが、急いで学ぶ必要はありません。既にRailsで使えるツールを現代的なフロントセットの思考様式に徐々に合わせていけばよいのです。 Sass vs. PostCSS SassはRailsに愛されています。しかし私たちの心はPostCSSに傾きつつあります。何より、PostCSSはRailsでCSSを処理するRuby組み込みのSassより36.4倍高速です。PostCSSは100%純粋なJavaScriptで書かれており、多くのプラグインを使って簡単に拡張/カスタマイズできます。cssnextというプラグインは、ブラウザでサポートされていない機能のポリフィルをすぐ使うことができますが、必要がなければ使わなくてよいのです。理由があれば、好みのプリプロセッサの上でPostCSSを使うこともできます。 私たちは何を作っているのか? そろそろ実際に手を動かさないといけませんね。フロントエンドの新しいアプローチをご紹介するために、最小限の認証とActionCableを用いた何の変哲もない標準的なチャットアプリを作ることにします。アプリ名はevil_chatとしました。このサンプルアプリは複雑ではありませんが、それでも「フルスタック」の経験に十分なぐらいに洗練されています。 私たちのプロジェクトでは、Asset PipelineやデフォルトのRailsジェネレータが生成する大量の.scssファイルや.coffeeファイルたちとおさらばすることにします。テンプレートエンジンは従来どおりERBを使い、好みに応じてSlimやHamlを使える余地を残しています。 左に見えるのがEvil Frontのフォルダ構造です 後でまたこのフォルダ構造を振り返ります。アプリのトップレベルにあるfrontendフォルダの中ですべてのことを行います。app/assetsは完全に置き換えられます。 一発ですべて理解できなくても問題ありません。ひとつずつ手順を追って進めましょう。 プロジェクトの開始方法 rails newだけでは不要なものを切り落とせないので、次の新しいマジックコマンドを使います(アプリ名はevil_chatとします)。 $ rails new evil_chat –skip-coffee –skip-sprockets –skip-turbolinks –webpack –database=postgresql -T ご覧のとおり、CoffeeScriptやSprockets関連の機能は不要になります。本チュートリアルではテスティングまではカバーしないので、-Tオプションでテストファイル作成をスキップしています。作成後Herokuにすぐデプロイできるよう、–database=postgresqlでPostgreSQLを指定しています。 一番肝心なのは–webpackオプションです。これを指定することで、Webpackですべてのアセットをバンドルするwebpacker gemがRailsで使われるようになります。 node_modulesフォルダにはJS依存ファイルがすべて含まれます(誤って余分なファイルを大量にリポジトリにコミットしないよう、.gitignoreにも追記されます)。 package.jsonはすべての依存関係を宣言します。yarn.lockも同様なので、npm installではなく(より機能豊富な)yarn addでパッケージを追加できます。 .babelrcファイルは、ES6を、マーケットシェア1%以上のあらゆるブラウザに準拠するJavaScriptコードに変換します。 .postcssrc.ymlはpostcss-smart-importプラグインやpostcss-cssnextプラグインで設定済みです。これらのプラグインのおかげで、cssnextに記載されている全機能を利用できます。 まだ何か忘れているような気がします。特に、Autoprefixerなどのツールのbrowserslistグローバル設定は、今後コードを正しくクロスブラウザ互換処理するうえで必要です。ありがたいことに、プロジェクトのルートディレクトリに以下のファイルを作成すれば簡単に修正できます。 $ touch .browserslistrc おかげで要求される知識が随分少なくなりました(まったくというわけにはいきませんが)。 それではこのファイルを開いて> 1%という1行を追加しましょう。これさえ知っておけばブラウザの互換性を保てます。 最初の段階で正しくやっておきたいことがもうひとつあります。Railsジェネレータのデフォルトの振る舞いの再設定です。既にネタバレしていますが、app/assetsには今後何も置く必要がないので、以下の手順でこのフォルダを削除します。application.rbを開いて以下の行を追記します。 # config/application.rb config.generators do |g| g.test_framework false g.stylesheets false g.javascripts false g.helper false g.channel assets: false end Asset Pipelineに引導を渡すときが来ました。app/assetsフォルダを削除します。 しかし置き換え方法はどうすればよいのでしょうか。次の手順を実行します。 rails newに–webpackオプションを追加したことでapp/javascriptというフォルダが作成されています。このフォルダをプロジェクトのルートに移動してフォルダ名をfrontendに変更します(名前は好みで構いませんが、frontendが一番わかりやすいと思います)。移動の際フォルダの中身は変更しないようにします。frontend/packsの中にあるapplication.jsは、このアプリのWebpack「エントリ」ポイントとして使われます。 application.html.erbを開き、javascript_include_tag “application”をjavascript_pack_tag “application”に置き換えます。メソッド名の単語が1つ変わることですべての違いが生じます。include_tagは、SproketsでコンパイルされたアプリレベルのJavaScriptファイルに参照を1つ挿入する昔ながらの方法ですが、pack_tagは先のエントリポイント(つまりfrontend/packs/application.js)から生成されたWebpackバンドルが使える新しい方法です。この段階で、<head>にあるpack_tagを<body>の末尾、つまりyieldステートメントの直前に移動します。 stylesheet_link_tag ‘application’, media: ‘all’をstylesheet_pack_tag ‘application’に置き換えます。WebpackとES6のimportステートメントの助けを借りて、今後はCSSをコンポーネント単位で使うことにします。これにより、CSSもすべてWebpackで管理されます。 次に、バンドルするファイルを探索する場所をWebpackerに指定する必要があります(デフォルトのフォルダをリネームしたので)。Webpacker 3.0によると、Railsのconfigフォルダ内にあるwebpacker.ymlで設定できます。このファイルの最初の数行に、以下の要領でアプリのフォルダ構造の変更を反映します。 default: &default source_path: frontend source_entry_path: packs public_output_path: packs cache_path: tmp/cache/webpacker ERBのパーシャルもfrontendフォルダ配下に置かれるので、application_controller.rbで次のように指定しないとコントローラから見つけられません。 # app/controllers/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery with: :exception # 以下を書くだけでよい prepend_view_path Rails.root.join(“frontend”) end Webpackerが3.0になったことで、開発中にオンデマンドでアセットをコンパイルするための別プロセスが不要になりました。しかしJSコードやCSSコードの変更時にページを自動更新するには、rails sするときに従来同様webpacker-dev-serverを実行しておく必要があります。そのためのProcfileが必要なので作成しましょう。 $ … Continue reading 新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳)