PureScriptでViteのCSSModuleサポートを使う

この記事は PureScript - Qiita Advent Calendar 2024 の8日目の記事です。

PureScriptでViteのCSSModuleを使う方法を解説していきます。

ViteでCSSModuleを使うにはJSファイルからimport文を使ってCSSをインポートするコードを書くことによって、CSSModuleを使うことができます。具体的なコードは次の通りです。

.foo { display: flex; }
import styles from './styles.module.css'

export const Foo = () => {
  return <div className=`${styles.foo}`></div>
}

しかし、PureScriptから直接 css ファイルをインポートする方法が存在しないので、このような直接的なアプローチでCSSModuleを使うことはできません。

そこで、PureScriptの FFI を用いてCSSをインポートするJSコードをPureScriptから呼び出すことでこの問題を回避することができます。

// Styles.js
import st from './styles.module.css'

export const styles = (name) => st[name]
-- Styles.Purs
module Components.Foo.Styles where

foreign import styles :: String -> String
-- 利用側
module Components.Foo where

import Components.Foo.Styles as Styles

-- | Viteで解決したCSSModuleの加工されたClassNameが取得できる
style :: String
style = Styles "foo"

これで spago build 自体は成功するのですが、viteでのモジュール解決が突破できません。viteはoutputディレクトリのspagoによってビルドされたファイルを見ますが、 spago build がやってくれるのはあくまでPureScriptのコンパイルとFFI用のJSをoutputディレクトリに配置してくれるだけで、CSSファイルは配置してくれないからです。

これを解決するためには、実際にCSSファイルを手でoutputディレクトリに配置してあげれば解決するのですが、ビルドの羃等性を破壊していたりCIでは動かすことができません。

解決策

冒頭の背景から次の問題が存在することがわかりました。

  • CSSファイル一つに対して、対応するFFI用のJavaScriptとFFIを使うためのPureScriptの実装を書く必要がある

  • spago build ではCSSファイルをoutputディレクトリに配置してくれないので、後続の vite build でCSSへのインポートが解決できずにエラーになってしまう。

これらの問題を解決するvite-pluginとして vite-plugin-css-class-name-extractor-for-purescript を実装しました。

このプラグインはこれらの問題をプラギンを読み込むだけで解決してくれます。 npm install vite-plugin-css-class-name-extractor-for-purescript を実行したら次のようなコードを vite.config.ts に記載するだけです。

import { defineConfig } from 'vite'
import classNameExtractor from 'vite-plugin-css-class-name-extractor-for-purescript'

export default defineConfig({
  plugins: [
    classNameExtractor()
  ]
})

このようにプラグインを読み込んだら、 npm run vite で vite-dev-serverを立ち上げてCSSを書くだけです。

デフォルトの設定では src/*/.module.css が編集される度に同階層のディレクトリにFFI用のJSとPureScriptを配置してくれるようになります。 また、起動開始時と編集にフックしてsrc/にあるCSSファイルをすべてoutputデイレクトリ内の対応したモジュールのディレクトリにmodule.cssを展開してくれるので、何もしなくても vite build が通るようになりスタイルが解決できるようになります。

また、stylesを直接exportせずに class名をPureScriptのAPIに変換することで利用側でクラス名を補完できるようにしました。

まとめ

PureScriptでViteのCSSModuleを使うためにVitePluginを作りました。

PureScriptでCSSModuleを使うためには様々なファイルを作る必要があって、TypeScriptで使う時に比べて面倒がおおかったですがVitePluginを導入することによって手間をTypeScriptでCSSModuleを扱うのと同じくらいにまで省略することに成功しました。

また、CSSのクラス名がAPIとして提供されることによって PureScriptファイルからclass名を補完できるようになって、TypeScriptでCSSModuleを使うよりも開発の体験が向上しました。

拍手ボタン