LoginSignup
32
33

More than 3 years have passed since last update.

Tailwind on Rails

Last updated at Posted at 2020-07-20

2020/1/15追記

Rails公式から、TailwindをRailsに組み込むためのgemが出たのでこっちの方が良いかもです。
https://github.com/rails/tailwindcss-rails

なぜTailwind on Rails?

  • クラス名を決める必要がなくなる
  • クラス名の衝突がなくなり、BEMやCSS設計から開放される
  • デザインの修正により不要になったCSSが残ってしまうことがなくなる
  • どの要素にどんなスタイルが当たっているかがすぐにわかる
  • カラーコードやフォントサイズ、ブレイクポイント等の統一性を保ちやすい
  • ネット上に転がっているサンプルコードを気軽に取り入れやすい(他の人が書いたコードでもカスタマイズが楽)
  • スタイルの修正のたびにapp/assets/stylesheets/任意のフォルダ/任意のファイルを開く必要がなくなる

環境

Rails 6.0.3

導入

$ yarn add tailwindcss
$ yarn tailwindcss init
$ mkdir app/javascript/css
$ touch app/javascript/css/tailwind.css
app/javascript/css/tailwind.css
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
app/javascript/packs/application.js
import '../css/tailwind.css';
postcss.config.js
module.exports = {
  plugins: [
    //...
    require("tailwindcss"), //追加
    require("autoprefixer"), //追加
    require("postcss-preset-env")({
      autoprefixer: {
        flexbox: "no-2009",
      },
      stage: 3,
    }),
  ],
};
app/views/layouts/application.html.erb
-  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
+  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 

動作確認

$ rails g controller test index
config/routes.rb
root to: 'tests#index'
app/views/tests/index.html.erb
<div class="max-w-sm mx-auto bg-white shadow-lg rounded-lg overflow-hidden">
  <div class="sm:flex sm:items-center px-6 py-4">
    <img class="block mx-auto sm:mx-0 sm:flex-shrink-0 h-16 sm:h-24 rounded-full" src="https://randomuser.me/api/portraits/women/17.jpg" alt="Woman's Face">
    <div class="mt-4 sm:mt-0 sm:ml-4 text-center sm:text-left">
      <p class="text-xl leading-tight">Erin Lindford</p>
      <p class="text-sm leading-tight text-gray-600">Customer Support Specialist</p>
      <div class="mt-4">
        <button class="text-purple-500 hover:text-white hover:bg-purple-500 border border-purple-500 text-xs font-semibold rounded-full px-4 py-1 leading-normal">Message</button>
      </div>
    </div>
  </div>
</div>

applyを使う

Tailwind CSSにはapplyという機能があり、複数のクラスをまとめて適用することができます。例えば同じボタンがあらゆる箇所に出現する場合、毎回font-bold py-2 px-4 rounded bg-red-500 text-white hover:bg-red-700などと書くのは大変なので、btnというクラスを指定するだけで上記のクラスを適用するためにapplyを使います。

【方法1】utilityの後に書く

この方法だと、widthのピクセル指定など、Tailwindのクラスでは表現できない部分のスタイルも指定できます。公式では、applyを使う場合utilityの前に書けと言われていますが、railsで使う場合utilityの後に書かないとうまく動作しませんでした。
※クラス名がユニークになるように気をつけてください。

app/javascript/css/tailwind.css
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
.btn {
  @apply font-bold py-2 px-4 rounded bg-red-500 text-white hover:bg-red-700;
  width: 300px;
}
app/views/tests/index.html.erb
<a href='#' class='btn'>ボタン</btn>

【方法2】helper関数で対応する

$ rails g helper tailwind
app/helpers/tailwind_helper.rb
module TailwindHelper
  def btn
    'fosnt-bold py-2 px-4 rounded bg-red-500 text-white hover:bg-red-700'
  end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  helper TailwindHelper
end
app/views/tests/index.html.erb
<a href='#' class='<%= btn %>'>ボタン</btn>

懸念点

TailwindCSSでは、想定されうるあらゆるユーティリティークラスが用意されているので、他のCSSフレームワークよりファイルサイズが大きいです。
この問題を、PurgeCSSという機能を使いビルド時に実際に使われているクラスに関するスタイルだけを抽出する方法で解決しています。

しかしRails上でTailwindを使う場合、PurgeCSSが使えません。(正確には設定方法がわかりません。分かる方がいたら教えてください。)
そのため通常よりファイルサイズが大きくなってしまいます。

解決しました↓↓↓

Purge CSS

使っているクラスのスタイルだけを抽出して、CSSのファイルサイズを軽くします。

$ yarn add @fullhuman/postcss-purgecss
postcss.config.js
let environment = { // 設定を変数にしまう
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
    require('postcss-import'),
    require('postcss-flexbugs-fixes'),
    require('postcss-preset-env')({
      autoprefixer: {
        flexbox: 'no-2009'
      },
      stage: 3
    }),
  ]
}

// 使っているクラスだけを抽出する設定
if (process.env.RAILS_ENV === "production") {
  environment.plugins.push(
    require('@fullhuman/postcss-purgecss')({
      content: [
        './app/**/*.html.erb',
        './app/**/*.js.erb',
        './app/helpers/**/*.rb',
      ],
      defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
    })
  )
}

module.exports = environment // エクスポート

デプロイ前後で、本番環境以下のコマンドを叩き、ファイルサイズが小さくなっていることを確認

$ RAILS_ENV=production bin/webpack

Asset       Size
css/application-72aa1758.css   20.2 KiB
css/application-72aa1758.css.map   6.54 KiB
js/application-dbc0495e28056a133c61.js    844 KiB
js/application-dbc0495e28056a133c61.js.map    898 KiB
manifest.json  640 bytes         

デプロイ後にエラーが発生した場合の対処

CapistranoでVPSにデプロイしたところ、ブラウザからアクセスできなくなってしまいました。
log/production.logを確認したところ、以下のようなエラーメッセージが記録されていました。

ActionView::Template::Error (Webpacker can't find application in /var/www/html/namatsuba/releases/20200728115729/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
  "application.js": "/packs/js/application-b63d405284038a2c85dc.js",
  "application.js.map": "/packs/js/application-b63d405284038a2c85dc.js.map",
  "entrypoints": {
    "application": {
      "js": [
        "/packs/js/application-b63d405284038a2c85dc.js"
      ],
      "js.map": [
        "/packs/js/application-b63d405284038a2c85dc.js.map"
      ]
    }
  }
}
):

原因

config/webpacker.ymlを確認すると、デフォルトでは本番環境だけcssをextractする設定になっているようでした。
capistranoデプロイ時に実行されるrake assets:precompileRAILS_ENV=productionなしで実行されており、extract_cssがfalseの状態でprecompileされてしまっていたことが原因だったみたいです。

解決策

config/webpacker.ymlを以下のように修正して解決。

config/webpacker.yml
- extract_css: false
+ extract_css: true

//...
production:
  <<: *default
  compile: false
  extract_css: true

参考

32
33
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
33