Ruby on RailsにViteとTailwindCSSを導入

前は`Webpack`を使っていましたが、設定などが難しいので辞めました。VueJSに慣れてから、VueJSの作者の作った`Vite`を使ってみて、早くて便利なので各プロジェクトに導入しました。

この記事は、既存のRailsアプリケーションに簡単に`Vite`と`TailwindCSS`を導入する方法をメモします。

## Viteを追加する

```ruby:Gemfile
gem 'vite_rails'
```

そして以下のコマンドでViteをインストールする

```zsh
vite install
```

`app/views/layouts/application.html.erb`に、`stylesheet_link_tag`と`javascript_importmap_tags`はもう必要ないので削除します。その代わりにVite専用タグを追加します。


```erb:app/views/layouts/application.html.erb
    <%= vite_client_tag %>
    <%= vite_javascript_tag 'application' %>
```

以下の部分を削除する

```erb:
    <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
```

`importmap.rb`も必要ないので削除する

```zsh
rm bin/importmap && rm config/importmap.rb
```

## Viteに便利だと思ったもの

### vite-plugin-full-reload

https://github.com/ElMassimo/vite-plugin-full-reload

`config/routes.rb`や`views/`などを編集したらページが自動的に再読み込み

```zsh
yarn add vite-plugin-full-reload -D
```

```ts:vite.config.ts
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
import FullReload from 'vite-plugin-full-reload' // 追加

export default defineConfig({
  plugins: [
    RubyPlugin(),
    FullReload(['config/routes.rb', 'app/views/**/*']) // 追加
  ],
})
```

### path

https://nodejs.org/docs/latest/api/path.html

`assets`フォルダなどを指定する時にショートカットで指定できる

```zsh
yarn add path
```

```js:vite.config.js
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
import FullReload from 'vite-plugin-full-reload'
import path from 'path' // 追加

export default defineConfig({
  plugins: [
    RubyPlugin(),
    FullReload(['config/routes.rb', 'app/views/**/*'])
  ],

  // 追加
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './app/assets')
    }
  }
})
```

例えば、assetsファイルをインポートする時に以下のような書き方ができ、管理しやすい。

```js:app/javascript/entrypoints/application.js
import '@/builds/index.css'
```

## TailwindCSSを追加する

実は`tailwindcss-rails`というGemが設定ファイルを自動作成してくれるが、本番リリース時のビルドに自由にカスタマイズしたいので使いません。
その代わりに、`tailwindcss-ruby`を使います。


```ruby:Gemfile
gem 'tailwindcss-ruby'
```

`tailwind.config.js`の設定ファイルを作成する

```tailwind.config.js
module.exports = {
  content: [
    './app/views/**/*',
    './app/helpers/**/*.rb',
    './app/javascript/**/*',
    './app/assets/stylesheets/**/*',
  ],

  theme: {
    extend: {
      colors: {
        primary: {
          light: '#047857',
          DEFAULT: '#065f46',
          dark: '#064e3b'
        }
      },
    },
  },

  darkMode: 'class',
  important: true
}
```

それから`application.scss`ファイルを作成する。

```scss:app/assets/stylesheets/application.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
```

`application.js`にビルドされたCSSをインポートする

```js:app/javascript/entrypoints/application.js
import '@/builds/index.css'
```

そして、`package.json`に以下の二つのスクリプトを追加する

```package.json
  "scripts": {
    "build:sass": "sass app/assets/stylesheets/application.scss:app/assets/builds/application.tailwind.css",
    "build:css": "tailwindcss -i ./app/assets/builds/application.tailwind.css -o ./app/assets/builds/index.css -c tailwind.config.js --minify"
  }
```

- build:sass
これは、sassコマンドを使って application.scss ファイルをコンパイルし、application.tailwind.css というCSSファイルを作成します。

- build:css
このスクリプトは tailwindcss コマンドを使って、application.tailwind.css から最終的な index.css を生成します。この過程で、tailwind.config.js の設定に従い、CSSの不要な部分を削除して最小化（圧縮）します。

`sass`コマンドが必要なのでインストールする

```zsh
gem i sass
```

次は`Prodfile.dev`

```Procfile.dev
web: rm -f tmp/pids/server.pid && env RUBY_DEBUG_OPEN=true bin/rails server
vite: bin/vite dev
sass: yarn build:sass --watch
css: yarn build:css --watch
```

上の設定によってのメリットは、`application.scss`への変更がある時に、自動的にCSSとTailwindCSSに変換されます。

例えば、`application.scss`に、以下のような豊富な書き方ができます。

```scss
// TailwindCSSの定義
@tailwind base;
@tailwind components;
@tailwind utilities;

// インポート
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
@import 'variables';
@import 'style';

// SCSSの書き方
html {
  body {
    font-family: "Inter", sans-serif;
    font-size: 16px;
  }
}

// TailwindCSSの書き方
.social-share-buttons {
  div {
    @apply p-2;
  }
  .social-share-button {
    @apply w-max cursor-pointer hover:bg-cyan-50 transition;
  }
}

```

ビルド済みのファイルを`.gitignore`に入れる

```.gitignore
/app/assets/builds/*
!/app/assets/builds/.keep
```

## ビルドしてみる

本番用のビルドをしてみて、ビルド成功したら完成です。

```zsh
rails assets:precompile RAILS_ENV=production
```

```zsh
yarn install v1.22.22
[1/4] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.04s.
Building with Vite ⚡️
yarn run v1.22.22
$ /Volumes/DATA/projects/myapp/node_modules/.bin/vite build --mode production
vite v5.4.10 building for production...
transforming...
✓ 2 modules transformed.
rendering chunks...
computing gzip size...
../../public/vite/.vite/manifest-assets.json       0.00 kB │ gzip: 0.02 kB
../../public/vite/.vite/manifest.json              0.25 kB │ gzip: 0.15 kB
../../public/vite/assets/application--rj0HET0.css  6.66 kB │ gzip: 1.93 kB
../../public/vite/assets/application-DNX3wj1L.js   0.18 kB │ gzip: 0.17 kB │ map: 1.12 kB
✓ built in 33ms
Done in 0.52s.
Build with Vite complete: /Volumes/DATA/projects/myapp/public/vite
```