Evil Front Part 1: railsでのモダンなフロントエンド
Evil Front Part 1: Modern Front-end in Rails — Martian Chronicles, Evil Martians’ team blog
フロントエンドのフレームワークに依存しない、Railsでのプレゼンテーションロジックの処理に関するモダンでモジュールベースのコンポーネントベースのアプローチに関する有益なガイドです。 3つの部分で構成されたチュートリアルに従うことで、最新のフロントエンド技術を学び、最終的にはそれをすべて理解することができます。 混乱している部分 イケてるRailsのフルスタックの開発者であることは、今日では大変な努力が必要です。 Asset Pipeline、Sprockets、CoffeeScript、Sassのフロントエンドを扱うための "classic Rails"の方法は、2017年に時代遅れになっています。 Rails 3.1の時代に作られた多くの物は、現代的なモダンアプリには向いているものではありません。 古い方法に固執するということは、過去半世紀にわたりフロントエンドコミュニティで起こったすべてを伝えることです。 JavaScriptパッケージマネージャーとしてのnpmの台頭、それらのすべてを支配するJSの出現、JSのシンタックスとしてのES6の登場、transpilersとビルドツールの勝利、CSSプリプロセッサの代替としてのPostCSSの採用 。 ReactやVueのようなフロントエンドフレームワークの驚異的な成功は言うまでもありませんが、フロントエンドコードについての考え方を変えています。つまり、「ページ」の代わりにコンポーネントという考え方です。 開発者の頭の中で複雑さをすべて詰め込もうとすると(特に始めたばかりの人にとっては)、認知的疲労が生じます。 しかし、「フロントエンドの人」と話すことの後ろめたさ、難しさ、そして仕事の見通しに対する不安は、確立されたワークフローに疑問を投げかけざるをえない。 結局、プログラマーは合理的な人です。 Asset Pipelineの何が問題なのですか? 「古い方法」はまだ機能しています。 効果を得るために、標準のRailsフロントエンド設定(そしてCoffeeScriptを使用)に依存しています。ビューテンプレート、スクリプト、およびスタイルは、Asset Pipelineによって引き続き処理されます。連結、縮小、配信されます。 プロダクションでは、すべてが重要で、スクリプト用とスタイル用の2つの大きなファイル(人間にとっては少なくともファイル)の形で提供されます。 開発者として、私たちは通常以下のことを気をつけます ・分離され、再利用可能で、テスト可能なコード ・短い「コード変更→分かり易い」サイクル ・直接的な依存関係管理 ・よく管理されたツール 確かに、 "古典的な" Railsは、コードをいくつかの構造に与えています。ビューテンプレート、JavaScript、スタイルシート、画像用に別々のフォルダがあります。しかし、フロントエンドの複雑さが増すにつれて、それらを迅速にナビゲートすることが当たり前の流れとなっています。 <b>"クラシック Rails フルスタック方法"に十分に注意を払わなければ、デッドコードが散らばったCSSとJSのグローバルなゴミ箱に、すぐになってしまうでしょう。</b> 速度もスイッチを考慮するもう一つの理由です。 問題は十分に文書化されていること、そしてHerokuにはAsset Pipelineのパフォーマンスを最適化する方法について専用ガイドがあり、AssetがRailsアプリケーションをデプロイするのが最も遅いことを認めています。: "平均して、バンドルインストールによる依存性のインストールより20倍遅いです。 開発中には、CSSの行を変更して結果を見るためにページを再ロードするのには時間がかかるかもしれません。 依存関係はどうですか? Asset Pipelineを使用すると、最新の状態に保つことは大変な労力となります。 プロジェクトにJavaScriptライブラリを追加するには、CDNからコードをロードし、app / assets、lib / assets、またはvendor / assetsにカットアンドペーストするか、または誰かがそれをgemに入れてくれるのを待つことができます。 一方、JavaScriptコミュニティでは、npm install、または最近ではYarn追加のコマンドを使用して同じことを管理しています。 同じことが更新に行きます。 YarnはJavaScriptのBundlerの便利さを私たちに提供します。 最後に、Asset Pipelineの背後にあるビルドツールであるSprocketsは、よく維持管理されていないようです。 変化 2017年、DHHとRailsのコミュニティはついに物事を変え始めました。 Rails 5.1はWebpackerとwebpackerの統合、Yarnによるnode_module、Babel、React、Vue、PostCSS(そしてElmの場合でも冒険的な気持ちであれば)のサポートを提供してくれました。 しかし、Asset PipelineとCoffeeScriptはまだあります。素のrailsを使ってプロジェクトを始めると、あなたは「良い方法」を得ることができます。 WebでJS関連のトピックを検索している最中でも、コード例をheadに入れておく必要があります。 しかし、あなたのRailsアプリケーションが現在のすべての現代の慣例を採用することができるように、心配しないでください。そして、我々は基礎を一緒にカバーするつもりです。 あなたが始める必要があるのは、Rails、JavaScript、CSSの基本的な知識です。 最新のRails 5.1+機能を活用して、最小限の設定とツーリングを維持します。 この一連のチュートリアルでは、現代感覚のフロントエンドを構築するためにEvil Martiansで開発されたベストプラクティスのいくつかを紹介します。リアクションは、私たちにコンポーネントを考えることを教えてくれます。他の最新のフロントエンドフレームワークが主導しています。モジュール性は、BEMなどの一般的なCSS手法の背後にある哲学です。アイデアは簡単です:あなたのUIのすべての論理部分は自己完結型でなければなりません。 Railsには、ビューを論理パーツビューパーシャルに分割する組み込みの方法があります。しかし、あなたの部分的なJavaScriptに依存している場合、現代的なコンポーネントがそうであるように、あなたはapp / assets / javascriptsの遠くのフォルダにそれを届かなければなりません。私たちがすべてを集めて、それぞれのスクリプトとスタイルを同じ場所にまとめることができたらどうでしょうか?そうすれば、実際に使用するコンポーネントだけをバンドルするために、最新のビルドツールの賢明さに頼ることができます。何かを変えたいときはいつでもどこを見ているのか正確に分かります。 React、Vue、またはElmのアーキテクチャーに頼るのではなく、意図的にそういうツールを自分で学習することは自由ですが、今は急いで学習する必要はありません。 Railsに付属のツールを使用して、徐々に最新のフロントエンドの考え方を採用することができます。 Sass vs. PostCSS RailsはSassが大好きです。しかし、私たちはPostCSSに固執する傾向があります。まず第一に、RailsでCSS処理を処理する組み込みのRuby Sassよりも36.4倍高速です。 100%純粋なJavaScriptで書かれています。数多くのプラグインで簡単に拡張可能でカスタマイズ可能です。そのうちの1つであるcssnextは、箱から出てきて、ブラウザでまだサポートされていない機能のポリフィルを生成します。また、理由を見つけた場合でも、お気に入りのプリプロセッサの上にPostCSSを使用することができます。私たちは何を構築していますか?ついに私たちの手を汚す時間です。フロントエンドに対する新しいアプローチを実証するために、最小限の認証とActionCableで標準的な即時チャットアプリケーションを構築します。それをevil_chatと呼んでみましょう。この例はそれほど複雑ではありませんが、私たちの経験を "フルスタック"にするにはまだ洗練されています。私たちのプロジェクトでは、Asset Pipelineと.scssファイルと.coffeeファイルを作成するデフォルトのRailsジェネレータに別れを告げるつもりです。私たちはデフォルトのテンプレートエンジンとしてERBを維持し、あなた自身のペースでSlimやHamlのような選択肢を探求していきます。左側には、Evil Frontのフォルダ構造フォルダ構造を再訪する予定です。アプリケーションのトップレベルにある新しいフロントエンドフォルダですべてが行われます。アプリ/アセットを完全に置き換えます。まだそれが意味をなさないと心配しないで、ステップバイステップでそれを取る。プロジェクトを開始するにはどうしたらいいですか?だから、裸のレールはもうそれをカットしません。あなたの新しい魔法の行は次のとおりです(アプリケーションの名前はevil_chatとします)。$ rails new evil_chat --skip-coffee --skip-sprockets --skip-turbolinks --webpack --database = postgresql -T CoffeeScriptやSprockets関連の機能が不要になりました。 -Tはオプションです。テストはこのチュートリアルの対象外ですので、テストファイルの作成はスキップします。 PostgreSQLは--database = postgresqlのデフォルトデータベースとして使用します。これは、完了後にHerokuでアプリケーションを簡単に展開できるようにするためです。最も重要なオプションは--webpackです。それはRailsにWebpackerの宝石を使ってすべての資産をWebpackに束ねるよう伝えます。今私たちのプロジェクトには、現代的なツールが用意されています:私たちのすべてのJS依存関係を含んでいるnode_modulesフォルダ(.gitignoreにも追加されていますので、間違いなくあなたのレポに何千もの追加ファイルをコミットしません)すべてのあなたの依存関係だけでなく、npmの代わりに(魅力的な)糸を追加してパッケージを追加することができることを意味する、yarn.lockという意味です。 .babelrcファイルは、ES6を現在市場シェアの1%を超えるブラウザに準拠したJavaScriptコードに変換するように設定されています。 .postcssrc.ymlは、cssnextで説明されているすべての機能を使用できるpostcss-importおよびpostcss-cssnextプラグインで既に設定されています。しかし、いくつかのことは忘れています。特に、ブラウザのリストのためのグローバルな設定、Autoprefixerのようなツールはブラウザ間での互換性を保つためにコードを正しく処理する必要があります。喜んで修正するのは簡単ですが、プロジェクトのルートにファイルを作成するだけです:$ touch .browserslistrcそうではありませんが、これほど多くの知識で確実に逃げることができます。それだけで、ブラウザの互換性について知っていることです!私たちが最初からうまくやったことは、Railsジェネレータのデフォルト動作を再設定することです。私たちは、アプリケーションや資産に何かを入れる必要はありません。(スポイラー!)次のステップでこのフォルダを完全に削除します。 application.rbを開き、次の行を追加します アセットパイプラインの冒涜を行う時間。 app / assetsフォルダを削除します。 しかし、それをどのように置き換えるのですか?次の手順を実行します: 私たちのレールの--webpackオプションは、app / javascriptという名前のフォルダを作成しました。それをプロジェクトのルートに移動し、フロントエンドに名前を変更します(または、あなた自身の名を選んでくださいが、 "フロントエンド"が最も理にかなっています)。内部はそのままにしておきます。フロントエンド/パック内のapplication.jsはWebpackの「エントリー」ポイントとして機能します。 application.html.erbに移動し、javascript_include_tag "application"をjavascript_pack_tag "application"に置き換えます。メソッド名の1つの単語がすべての違いをもたらします:include_tagは、Sprocketsによってコンパイルされたアプリケーション全体のJavaScriptファイルへの参照を挿入します(旧形式)、pack_tagは、エントリーポイントから生成されたWebpackバンドルを取り込みます。 .js(新しい方法)。その間、yieldタグの直後にpackタグを<body>の<head>から最後まで移動します。 stylesheet_link_tag 'application'、media: 'all'をstylesheet_pack_tag 'application'に置き換えます。 WebpackとES6のimportステートメントの助けを借りて、コンポーネントごとにCSSを使用します。つまり、私たちのスタイルはすべてWebpackerによって処理されます。 ここで、デフォルトのフォルダの名前を変更したので、バンドルするファイルの場所をwebpackerに知らせる必要があります。 webpacker 3.0以降は、Railsのconfigフォルダ内のwebpacker.ymlファイルを通して設定が行われます。最初の数行は、フォルダ構造の変更を反映するために次のように見えるようにしてください。 デフォルト:&default source_path:フロントエンド source_entry_path:パック public_output_path:パック cache_path:tmp / cache / webpacker 私たちのERBパーシャルはフロントエンドフォルダにも存在するでしょう。そして、私たちがapplication_controller.rbでそうしない限り、コントローラーはそれらを見つける方法を知らないでしょう: #app / controllers / application_controller.rb クラスApplicationController <ActionController :: Base protect_from_forgeryを使って::例外 #それはすべてあります: prepend_view_path Rails.root.join( "frontend") 終わり webpacker 3.0以降、開発時にアセットをオンデマンドでコンパイルするための別個のプロセスは必要ありませんが、JS / CSSコードの変更ごとに自動ページリフレッシュを使用するには、webpacker-dev-サーバーとレールが並んでいます。そのためにはProcfileが必要なので、作成しましょう: $ touch Procfile これを内部に入れてください: サーバ:bin / railsサーバ assets:bin / webpack-dev-server Procfileを使用すると、Foremanのようなツールを使用して1つのコマンドですべてのプロセスを起動できますが、Hivemindの代わりに使うことを強くお勧めします。また、実行中のプロセスを中断することなくデバッグのためにpryを使うことができるので、兄のOvermindを見てみることもできます。 煙のテスト 新しいセットアップが正しく動作しているかどうかをテストする時間。私たちのapplication.js(packsの下にあります)にいくつかの簡単なコードを追加して、DOMを操作し、webpackerがそれをうまく処理できるようにしましょう。まず、基本的なコントローラを生成し、デフォルトルートを提供する必要があります。 $ rails gコントローラページホーム #config / routes.rb Rails.application.routes.draw do root: "ページ#home" 終わり views / pages / home.html.erbからすべてを削除するようにしてください。コードはまったく含まれていません。今application.jsにあるすべてのものを削除し、これで置き換えてください: // frontend / packs / application.js インポート "./application.css"; document.body.insertAdjacentHTML( "afterbegin"、 "Webpacker works!"); 同じフォルダにapplication.cssファイルを作成して、私たちのスタイルもPostCSSで処理されていることを確認してみましょう。 / * frontend / packs / application.css * / html、body { 背景:ライトイエロー; } 初めてサーバーを起動する時間!私たちはあなたがすでにHivemindをインストールしているとします。使用していない監督やそれに類するプロセスマネージャがいるとします(しかし、真剣に、Hivemindを考えてみてください)。 $ hivemind 次に、http:// localhost:5000に行きます(Hivemindは$ PORT環境変数を5000に設定し、Railsは同じ変数を使用して実行するポートを決定します)。 アプリのスモークテスト それが燃えない場合、それは動作します! そして、ここでWebpackについてのすばらしいことがあります。 application.jsに行って "Webpacker works!"を何かに変更してファイルを保存すると、ブラウザに "更新"ボタンを押さなくても変更が表示されます。 さて、実際のコードを書く前に、それをスタイルで書くようにしましょう。 さて、どうやって私のJSを舐めますか? Prettierは人気の高いエディタと統合されているので、ボタンを押すだけでコードを再フォーマットすることができます。 ESLintには、すべてのメインエディタ用のプラグインがあり、すぐに視覚的なフィードバックを得ることができます。 JavaScriptを書くにはたくさんの方法がありますし、毎年構文が更新されているので、始める前に混乱するのはとても簡単です。セミコロン/セミコロンのない議論は決して古くはありません。 JavaScriptシンタックスのそれぞれの特長を議論するのではなく、StandardやPrettierのような有名なコードフォーマッタを使用する方が簡単です。私たちはPrettierを選択します(そして、はい、デフォルトではセミコロンが付きますが ESLintを使って自動化されたリンキングを設定する予定ですので、コードスタイルは常にチェックされています。また、保守可能なJSコードを書くためのベストプラクティスの多くを含むAirbnb JavaScript Style Guideにも依存しています。 私たちのpackage.jsonにいくつかのdevDependenciesを追加しましょう。今のところ、webpack-dev-serverだけが含まれています。これは、JS lintingのニーズに応えるようにした後の様子です。 { "name": "evil_chat_codealong"、 "private":true、 "依存関係":{ "@ rails / webpacker": "^ 3.2.0" }、 "devDependencies":{ "webpack-dev-server": "^ 2.9.1"、 "babel-eslint": "^ 8.0.1"、 "eslint": "^ 4.8.0"、 "eslint-config-airbnb-base": "^ 12.0.1"、 "eslint-config-prettier": "^ 2.6.0"、 "eslint-import-resolver-webpack": "^ 0.8.3"、 "eslint-plugin-import": "^ 2.7.0"、 "eslint-plugin-prettier": "^ 2.3.1"、 "lint-staged": "^ 4.2.3"、 "pre-commit": "^ 1.2.2"、 "よりきれいな": "^ 1.7.3" } } lint-stagedとpre-commitは、git addコマンドとgit commitコマンドにいくつかのフックを追加すると便利です。このようにして、あまり理想的ではないコードがリポジトリに決してそれを作らないようにします。 最後の1つのタッチ:ルートフォルダに.eslintrcファイルが必要です。そのため、ESLintはルールを適用する方法を知っています。 $ touch .eslintrc これを内部に入れてください: { "extend":["eslint-config-airbnb-base"、 "prettyttier"]、 "プラグイン":["もっときれい"]、 "env":{ "browser":true }、 "rules":{ "もっときれい": "エラー" }、 "parser": "babel-eslint"、 "設定": { "import / resolver":{ "webpack":{ "config":{ "解決する":{ "modules":["frontend"、 "node_modules"] } } } } } } 「拡張」キーの要素の順序は重要です。この方法では、ESLintにAirbnbルールを最初に適用するように指示しています。また、以前のフォーマットガイドと競合する場合は最新のものを優先します。また、eslint-import-resolver-webpackの依存関係にキー "import / resolver"を追加する必要があります。JSファイルにインポートするものは、実際にWebpackが扱うフォルダに存在します(この場合、フロントエンドですフォルダ)。 CSSはどうですか? CSSはあまりにも糸を引く必要があります!私たちはまた、尊重されたツールnormalize.cssを使って正規化します。私たちはスタイルシートのスタイル違反や慣習違反を検出するためにstylelintに依存しています。 package.jsonにさらに2つの開発依存関係を追加しましょう: "devDependencies":{ ... "stylelint": "^ 8.1.1"、 "stylelint-config-standard": "^ 17.0.0" } また、私たちのルートに.stylelintrcファイルが必要です - 私たちのリンターに指示してください。 $ touch .stylelintrc 内部: { "extends": "stylelint-config-standard" } また、package.jsonの "dependencies"キーの下にnormalize.cssを追加してください(今回はdevDevdependenciesではありません!)ので、あなたのパッケージリストの一部が次のようになります: "依存関係":{ "@ rails / webpacker": "^ 3.2.0"、 "normalize.css": "^ 7.0.0" }、 ... 今度はいくつかのgitフックを導入して、すべてのチェックが各git commitで自動的に実行されるようにしましょう。そのために、私たちはpackage.jsonに "scripts"キーを追加します: ... "scripts":{ "lint-staged": "$(yarn bin)/ lint-staged" }、 "lint-staged":{ "config / webpack / ** / *。js":[ "よりきれいな - 書き込み"、 "eslint"、 "git add" ]、 "frontend / ** / *。js":[ "よりきれいな - 書き込み"、 "eslint"、 "git add" ]、 "frontend / ** / *。css":[ "よりきれいな - 書き込み"、 "stylelint --fix"、 "git add" ] }、 "pre-commit":[ 「糸くずの段階」 ]、 ... 現在、コミットするたびに、ステージングされたすべてのファイルのエラーが検査され、自動的に再フォーマットされます。 最終的なpackage.jsonは、この要点の内容のように見えるはずです。 新しい依存関係をすべてインストールするには、端末で糸を実行します。 自動化されたリンチングが実際に動作するのを待つことはできません。あなたのfrontend / packs / application.jsに行き、セミコロンを削除してみてください。次に、git addを実行します。 && git commit -m "JS lintingをテストする"とセミコロンがすぐに追加されるのを見てください。見る?もう駄目なスタイルはありません。 リンターの設定 すべてが正しく設定されていれば、プロジェクトのルートにはすべてのファイルが含まれているはずです 私たちの最初のコンポーネント(Reactは関係しません) このガイドの第2部で何が起こるのかを知るために、最初のコンポーネントを作成してみましょう。 まず、application.cssを取り除きましょう。私たちは煙のテストのためだけに必要でした。 application.jsからすべてのコードも削除してください。これからのapplication.jsにはimport文しか含まれません。このエントリーポイントは、すべてが一緒になる場所です。アプリ全体のスタイルシートやJavaScriptを保持するためには、別の場所が必要になるので、作成しましょう。この新しいフォルダinitと呼ぶことにします。 $ mkdir frontend / init $ touch frontend / init / index.js $ touch frontend / init / index.css 今度は、新しいフォルダをエントリーポイントに登録する必要があります。 packs / application.jsに次の行を追加します。 // frontend / packs / application.js import "init"; そして今、私たちの新しいファイルのためのいくつかのコード。ここにinit / index.jsがあります: // frontend / init / index.js インポート "./index.css"; そして、f init / index.cssの場合: / * frontend / init / index.css * / @import "normalize.css / normalize.css"; 体 { font-family: "Helvetica Neue"、Helvetica、Arial、sans-serif; font-size:16px; 行の高さ:24ピクセル。 } ここでは、アプリのすべてのフォントに一般的なスタイルを適用しています。私たちのinitフォルダも最初にバンドルされるので、ここでは私たちのnormalize.cssをインクルードするのが理にかなっています。後で、同じフォルダを使用して、ポリフィルまたはエラー監視を設定することができます。これらの機能は、コンポーネントに直接関係なく、できるだけ早くロードする必要があります。 さて、initは特殊なケースなので、コンポーネントはどうですか? 各コンポーネントは、ERBパーシャル用、スクリプト用、およびスタイル用の3つのファイルを含むフォルダです。 すべてのコンポーネントはフロントエンドのcomponentsフォルダにあります。単にページと呼ばれる最初のコンポーネント(レイアウトのテンプレートとして考えてください)を作成しましょう: $ mkdir -p frontend / components / page $ touch frontend / components / page / {_ page.html.erb、page.css、page.js} コンポーネントのJSファイルindex.jsを呼び出さないことに注意してください。この名前はinitフォルダ用に予約されています。 JSファイルをコンポーネントと同じ名前にして、後でエディタに複数のタブが開いているときに、どこにいるのかをすぐに把握できるようにします。この方法は一般的ではありません(他のチュートリアルでは、ほとんどの場合、コンポーネントのindex.jsが表示されます)が、コードを書くときには時間が大幅に節約されます。 まだコンポーネント関連のJSロジックはありません。そのため、私たちのpage.jsはCSSファイル用の1つのimportステートメントで構成されています。 // frontend / components / page / page.js インポート "./page.css"; 私たちのpage.cssにはいくつかのコンポーネント関連のスタイルがあります: / * frontend / components / page / page.css * / .page { 高さ:100vh; 幅:700px; マージン:0 auto; オーバーフロー:隠された; } 最後に、_page.html.erbにはマークアップが含まれています。ここでは、すべてのERB製品を使用して、コンポーネントを入れ子にできるyield文を活用することができます。 <! - frontend / components / page / _page.html.erb - > <div class = "page"> <%=収率%> </ div> import "components / page / page"を追加して、application.jsの新しいコンポーネントを参照することを忘れないでください。 第1成分の構造 チュートリアルのこの時点での "フロントエンド"フォルダの構造 次に、home.html.erbビューにERBコードを追加しましょう。 <! - app / views / pages / home.html.erb - > <%= "コンポーネント/ページ/ページ"を表示する%do> <p>最初のコンポーネントからのお誘い!</ p> <%end%> 私たちの最初のコンポーネントが実際に見える時間!サーバーをもう一度起動し、ページを更新します。指が交差したら、あなたはそのようなものを見るつもりです: 第1成分の構造 最初に動作するコンポーネント用のブラウザとコンソール出力 このチュートリアルの第1回を完了しました。パート2に進み、アプリケーションが最終的に形を整え、チャット関連の機能に必要なコンポーネントを紹介してください。また、入力を少なくしてコンポーネントをレンダリングするヘルパーと、作成を自動化するジェネレータも追加しました。