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
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
import '../css/tailwind.css';
module.exports = {
plugins: [
//...
require("tailwindcss"), //追加
require("autoprefixer"), //追加
require("postcss-preset-env")({
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
}),
],
};
- <%= 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
root to: 'tests#index'
<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の後に書かないとうまく動作しませんでした。
※クラス名がユニークになるように気をつけてください。
@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;
}
<a href='#' class='btn'>ボタン</btn>
【方法2】helper関数で対応する
$ rails g helper tailwind
module TailwindHelper
def btn
'fosnt-bold py-2 px-4 rounded bg-red-500 text-white hover:bg-red-700'
end
end
class ApplicationController < ActionController::Base
helper TailwindHelper
end
<a href='#' class='<%= btn %>'>ボタン</btn>
##懸念点
TailwindCSSでは、想定されうるあらゆるユーティリティークラスが用意されているので、他のCSSフレームワークよりファイルサイズが大きいです。
この問題を、PurgeCSSという機能を使いビルド時に実際に使われているクラスに関するスタイルだけを抽出する方法で解決しています。
しかしRails上でTailwindを使う場合、PurgeCSSが使えません。(正確には設定方法がわかりません。分かる方がいたら教えてください。)
そのため通常よりファイルサイズが大きくなってしまいます。
解決しました↓↓↓
Purge CSS
使っているクラスのスタイルだけを抽出して、CSSのファイルサイズを軽くします。
$ yarn add @fullhuman/postcss-purgecss
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:precompile
がRAILS_ENV=production
なしで実行されており、extract_cssがfalseの状態でprecompileされてしまっていたことが原因だったみたいです。
解決策
config/webpacker.yml
を以下のように修正して解決。
- extract_css: false
+ extract_css: true
//...
production:
<<: *default
compile: false
extract_css: true