Tech Racho エンジニアの「?」を「!」に。
  • 開発

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

概要

原著者の許諾を得て翻訳・公開いたします。

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

前書き

本記事は、フロントエンドのフレームワークに依存しないRailsプレゼンテーションロジックを現代的かつモジュール単位かつコンポーネントベースで扱う方法を独断に基いて解説するガイドです。3部構成のチュートリアルで、例を元に最新のフロントエンド技術の最小限に学習し、Railsフロントエンド周りをすべて理解しましょう。

Part 2Part 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/assetslib/assetsvendor/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を使える余地を残しています。

A new frontend folder in your app

左に見えるのが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.ymlpostcss-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が必要なので作成しましょう。
$ touch Procfile

このファイルに以下の設定を書きます。

server: bin/rails server
assets: bin/webpack-dev-server

このProcfileを置くことで、Foremanなどのツールを使ってすべてのプロセスをコマンド一発で起動できるようになりますが、Evil MartiansのHivemindをぜひおすすめいたします。Hivemindの兄貴分であるOvermindは実行中のプロセスを一時停止せずにpryでデバッグできるツールですので、こちらもご覧ください。

訳注: 同社は昔のSFになぞらえた命名を好んでいるようです。Hivemindは集合精神、Overmindは「幼年期の終わり」に登場する神っぽい宇宙規模の集合知性を指します。

スモークテスト

それでは新しいセットアップが正しいかどうかテストしましょう。application.jspacksの下にあります)にシンプルなDOM操作コードを少し足し、Webpackerでちゃんと動くようにします。最初に、基本となるコントローラとデフォルトルーティングをそれぞれ生成する必要があります。

$ rails g controller pages home
# config/routes.rb
Rails.application.routes.draw do
  root to: "pages#home"
end

views/pages/home.html.erbの中身は完全にからっぽにしてください。次にapplication.jsの中身もからっぽにし、以下のコードに置き換えます。

// frontend/packs/application.js
import "./application.css";

document.body.insertAdjacentHTML("afterbegin", "Webpacker works!");

同じフォルダにapplication.cssファイルを作成し、CSSも効いていることを確認できるようにします(CSSはPostCSSで処理されます)。

/* frontend/packs/application.css */
html, body {
  background: lightyellow;
}

いよいよアプリの初立ち上げです。Hivemindをインストール済みであることが前提です。インストールしない場合はforemanなどのプロセス管理ツールをお使いください(私たちとしてはぜひHivemindの素晴らしさをご検討いただければと思います)。

$ hivemind

ではhttp://localhost:5000を開きましょう(Hivemindは$PORTに5000を設定するので、Railsも同じ環境変数で実行ポートを決定します)。次のように表示されるはずです。

A smoke test for our app

真っ赤なエラー画面が出ていなければ成功です

ここでWebpackのクールな点を1つご紹介します。application.jsファイルで"Webpacker works!"の部分を変更して保存すると、ブラウザの[更新]ボタンを押さなくても画面が自動更新されます。

実際のコードを書き始める前に、コーディングスタイルを定めましょう。

ところでJSのlintはどうする?

Prettierには著名なエディタがすべて統合されているので、ボタンひとつでコードを整形できます。ESLintにもあらゆる主要なエディタ向けのプラグインがあるので、即座に結果をビジュアル表示できます。

JavaScriptの文法は年単位で更新を繰り返すので、コーディングスタイルは多岐にわたり、書き始める前からスタイルが混乱しがちです。たとえばセミコロン使う派と使わない派の争いは終わりそうにありません。StandardPrettierのように、独自の色を出すコードフォーマッタもあります。私たちはPrettierにしました(Prettierはデフォルトでセミコロンを使いますが、いつでもオフにできます)。

lintはESLintである程度自動化するので、コーディングスタイルは常にチェックされます。また、メンテしやすいJSコードを書くベストプラクティスを豊富に収録しているAirbnbのJavaScriptスタイルガイドにも頼ることにします。

訳注: AirbnbのJavaScriptスタイルガイド日本語版は以下をどうぞ

JavaScriptスタイルガイド 1〜8: 型、参照、オブジェクト、配列、関数ほか (翻訳)

現時点ではwebpack-dev-serverしか含まれていないpackage.jsondevDependenciesを少々追加します。JavaScriptのlintに必要な部分をカバーすると、以下のような感じになるはずです。

{
  "name": "evil_chat_codealong",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "^3.0.1"
  },
  "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",
    "prettier": "^1.7.3"
  }
}

lint-stagedpre-commitは、後でgit addgit commitなどにフックするときに便利です。これは、残念なコードを誤ってリポジトリに登録しないようにするためのものです。

最後の仕上げに、ルートフォルダに.eslintrcファイルが必要です。適用するルールをESLintに指示するのに使います。

$ touch .eslintrc

.eslintrcに以下を書きます。

{
  "extends": ["eslint-config-airbnb-base", "prettier"],

  "plugins": ["prettier"],

  "env": {
    "browser": true
  },

  "rules": {
    "prettier/prettier": "error"
  },

  "parser": "babel-eslint",

  "settings": {
    "import/resolver": {
      "webpack": {
        "config": {
          "resolve": {
            "modules": ["frontend", "node_modules"]
          }
        }
      }
    }
  }
}

"extends"キー以下の要素の順序は重要です。ここで、最初にAirbnbのルールを適用し、Prettierのフォーマットガイドとコンフリクトするものがあれば常に最新のものを使うようESLintに指示しています。eslint-import-resolver-webpackへの依存を指定する"import/resolver"キーも必要です。これによって、JSファイル内のimportで指定したライブラリが、Webpackが管理するフォルダ(このアプリの場合はfrontendフォルダ)内に実際に存在するようになります。

CSSはどうする?

CSSにも何かlintツールが必要です。評判のよいツールであるnormalize.cssをnormalizeに使うことにします。CSSのエラーやスタイル違反の検出用にstylelintも使います。package.jsonに開発用の依存ライブラリを2つ追加しましょう。

"devDependencies": {
    ...
    "stylelint": "^8.1.1",
    "stylelint-config-standard": "^17.0.0"
  }

プロジェクトのルートフォルダに.stylelintrcを置いてlinterに指示する必要もあります。

$ touch .stylelintrc

ファイルの中身は次のとおりです。

{
  "extends": "stylelint-config-standard"
}

package.json(今度はdevDevdependenciesではありません!)の"dependencies"キーの配下に次のようにnormalize.cssを追加します。

"dependencies": {
    "@rails/webpacker": "^3.0.1",
    "normalize.css": "^7.0.0"
  },
  ...

次はgit hooksをいくつか導入し、git commit時に自動チェックが走るようにしましょう。package.json"scripts"を追加します。

...
"scripts": {
    "lint-staged": "$(yarn bin)/lint-staged"
  },
  "lint-staged": {
    "config/webpack/**/*.js": [
      "prettier --write",
      "eslint",
      "git add"
    ],
    "frontend/**/*.js": [
      "prettier --write",
      "eslint",
      "git add"
    ],
    "frontend/**/*.css": [
      "prettier --write",
      "stylelint --fix",
      "git add"
    ]
  },
  "pre-commit": [
    "lint-staged"
  ],
  ...

これで、コミット時にstagedファイルのエラーがすべてチェックされ、自動整形されます。

最終的なpackage.jsongistにあるような形になるはずです。ターミナルでyarnを実行して依存ライブラリをインストールします。

自動lintを早く使ってみたくてウズウズしているかと思います。frontend/packs/application.jsを開いてセミコロンを削除してから、git add . && git commit -m "testing JS linting"を実行すると、ただちにセミコロンが復元されます。だらしないコーディングスタイルともこれでお別れです。

Linterの設定

設定がすべて正しければ、プロジェクトのルートファイルにこれらのファイルがすべてあるはずです

最初のコンポーネント(React未使用)

本ガイドのPart 2で扱う内容の一部を軽くご紹介します。最初のコンポーネントを作ってみましょう。

最初にapplication.cssを削除します。これはスモークテスト以外では不要です。同様にapplication.jsのコードもすべて削除します。ここからは、application.jsにはimportステートメントだけを書きます。このエントリポイントにすべてが集約されます。アプリ全体で使うCSSや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
import "./index.css";

以下はinit/index.cssです。

/* frontend/init/index.css */
@import "normalize.css/normalize.css";

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 24px;
}

ここでは、アプリのすべてのフォントに一般的なスタイルをいくつか適用しています。initフォルダはバンドル時に最初にチェックされる場所なので、ここにnormalize.cssをインクルードするのが自然です。同じフォルダを使って、後でポリフィルやエラー監視など、私たちのコンポーネントに直接関係のない機能をセットアップして必要が生じたら可能な限り読み込むこともできます。

initは特殊ケースです。このコンポーネントについてはどうでしょうか。

各コンポーネントは、3つのファイル(ERBパーシャルとそれ用のJS/CSSファイル)を含む1つのフォルダで構成されます。

私たちのコンポーネントはすべて、frontend配下のcomponentsフォルダ内に置かれます。ここに最初のコンポーネントを作成しましょう。レイアウトのテンプレートとみなしてこのコンポーネントをpageと呼ぶことにします。

$ 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ファイルをimportする行しかありません。

// frontend/components/page/page.js
import "./page.css";

page.cssの方にはコンポーネントに関連するスタイルがあります。

/* frontend/components/page/page.css */
.page {
  height: 100vh;
  width: 700px;
  margin: 0 auto;
  overflow: hidden;
}

最後の_page.html.erbにはマークアップが含まれています。ERBや、コンポーネント同士をネストするのに使うyieldステートメントもすべて使える点にご注目ください。

<!-- frontend/components/page/_page.html.erb -->
<div class="page">
  <%= yield %>
</div>

application.jsimport "components/page/page";を追加して、新しいコンポーネントを参照できるようにするのをお忘れなく。

A structure for the first component

この時点でのfrontendフォルダ構造

それではhome.html.erbビューにERBコードを書いてみましょう。

<!-- app/views/pages/home.html.erb -->
<%= render "components/page/page" do %>
  <p>Hello from our first component!</p>
<% end %>

最初のコンポーネントが実際に動作することを確認しましょう。サーバーを再び起動してページを更新します。うまく行けば、以下のように表示されるでしょう。

A structure for the first component

最初のコンポーネントのブラウザ表示とコンソール出力

おめでとうございます。チュートリアルPart 1はこれでおしまいです。ぜひPart 2もご覧いただき、アプリの体裁を整えてチャット関連の機能に必要なコンポーネントを導入するところまでやってみてください。少ないコード量でコンポーネントをレンダリングするヘルパーや、コンポーネント作成を自動化するジェネレータも追加します。


Part 1 | Part 2 | Part 3

スタートアップをワープ速度で成長させられる地球外エンジニアよ!Evil Martiansのフォームにて待つ。

関連記事

Rails 5.2ベータがリリース!内容をざっくりチェックしました

5.1 beta1リリースノートに見るRails 5.1の姿


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。