💨

Expo RouterでNativeWind(Tailwind CSS)を使用する

2024/01/29に公開

はじめに

React NativeのプロジェクトでTailwind CSSを使用可能にするNativeWindというライブラリがあります。
https://www.nativewind.dev/

Web環境ではCSS StyleSheet、Native環境ではStyleSheet.createをそれぞれ出力しTailwind CSSを実現しているようです。Native環境で使用する場合、Webで使用可能なユーティリティクラスが一部使えないなどの制約がありますが現在開発が進められており日々進化を続けています。

今回はExpo Routerが導入されたプロジェクトにNativeWindを新規に導入し、使用可能になるまでの流れを解説します。

新規プロジェクト作成

Expoが提供しているcreate-expo-appを利用して新規プロジェクトを作成します。
--templateオプションをつけて実行すると既にExpoが用意しているテンプレートからプロジェクトを始めることができます。

$ bunx create-expo-app nativewind-app --template

テンプレートの選択を求められるので、Navigation (TypeScript)を選択します。

? Choose a template: › - Use arrow-keys. Return to submit.
    Blank - a minimal app as clean as an empty canvas
    Blank (TypeScript)
❯   Navigation (TypeScript)
    Blank (Bare)

作成したプロジェクトが起動できることを確認します。

$ bun run start

Expo Goやシミュレーターを使用してサンプルアプリを開けることを確認します。

Navigationサンプル画像

NativeWindセットアップ

パッケージ導入

expo installを使用して必須パッケージをまとめて導入します。

$ bunx expo install nativewind@^4.0.1 react-native-reanimated tailwindcss

プロジェクトルートにiosディレクトリがある場合は下記のコマンドを実行してください。
本記事の手順で、Expoのテンプレートから始めた場合は実行不要です。

$ bunx pod-install

導入するパッケージはこれだけです。続けてReact NativeへNativeWindを使用してTailwind CSSを反映するために必要な設定を進めていきます。

設定ファイル作成

Tailwind CSSの設定ファイルであるtailwind.config.jsを作成します。
パッケージのインストールに続けて以下のコマンドを実行します。

$ bunx tailwindcss init

実行するとプロジェクトのルートにtailwind.config.jsが新しく生成されます。

生成された設定ファイルを以下のように書き換えます。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
+  content: ["./app/**/*.{js,jsx,ts,tsx}"],
+  presets: [require("nativewind/preset")],
  theme: {
    extend: {},
  },
  plugins: [],
}

content: []の箇所にTailwind CSSを適用する対象のファイルの場所を記述します。
デフォルトでは./app/**/*.{js,jsx,ts,tsx}となっており./appの配下にあるファイルへ自動適用されます。

また、Expo RouterではNext.jsなどのフレームワークでよく見られる、srcディレクトリが標準サポートされています。srcディレクトリを使用する場合は./src/**/*.{js,jsx,ts,tsx}にする必要があります。
https://docs.expo.dev/router/reference/src-directory/

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
-  content: ["./app/**/*.{js,jsx,ts,tsx}"],
+  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  presets: [require("nativewind/preset")],
  theme: {
    extend: {},
  },
  plugins: [],
}

CSSファイル作成

Tailwind CSSで使用するCSSファイル(global.css)を新規作成します。

$ touch ./global.css

以下の3行を記述します。

global.css
@tailwind base;
@tailwind components;
@tailwind utilities;

Babelの設定変更

以下のようにbabel.config.jsを修正します。

babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
-   presets: ['babel-preset-expo']
+   presets: [
+     ["babel-preset-expo", { jsxImportSource: "nativewind" }],
+     "nativewind/babel",
+   ],
+   plugins: ['react-native-reanimated/plugin'],
  };
};

Metroの設定変更

metro.config.jsの設定を変更します。
プロジェクトルートにmetro.config.jsが存在しない場合は下記のコマンドで生成できます。

$ bunx expo customize metro.config.js

生成されたmetro.config.jsを下記のように書き換えます。

metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require('nativewind/metro');

const config = getDefaultConfig(__dirname)

module.exports = withNativeWind(config, { input: './global.css' })

型参照の追加

TypeScriptで正しく形定義の参照ができるようプロジェクトのルートにnativewind-env.d.tsを新規作成します。

$ touch nativewind-env.d.ts

下記の定義を追加します。

nativewind-env.d.ts
/// <reference types="nativewind/types" />

CSSのインポート

アプリのエントリーポイントとなるコンポーネントで先ほど作成したglobal.cssをインポートします。
Expo Routerの場合はデフォルトでapp/_layout.tsxが一番親のコンポーネントになります。

_layout.tsxの先頭へ下記の一行を追加します。

_layout.tsx
import "@/global.css"

これにてExpo RouterへNativeWindの導入は完了です。プロジェクト内でTailwind CSSを使用する準備ができました。

ここまで記載したら、一旦キャッシュをクリアしアプリを起動します。

$ bun run start -c

Expo Goや各種シミュレーターを使用してアプリが正常に表示できることを確認します。

エラーなどがなくアプリを起動できれば問題ありません。エラーが表示される場合は手順を確認のうえ漏れがないか見直しを行ってください。

NativeWindを試す

導入したNativeWindを使用して簡単なページを作成します。
Expo Routerではappディレクトリを起点としてルーティングが自動生成されます。

(tab)グループの中に新しいルート(/wind)を作成します。

$ touch app/(tabs)/wind.tsx

Tab Windページの内容を記載します。

wind.tsx
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { Text, View } from "@/components/Themed";

export default function WindScreen() {
  return (
    <View className="flex-1 items-center justify-center">
      <MaterialCommunityIcons size={48} name="tailwind" color="#1AB3BA" />
      <Text className="text-2xl font-bold underline">Hello, NativeWind!</Text>
    </View>
  );
}

タブバーへボタンを新規追加します(コードが長くなるため一部抜粋)
<Tabs.Screen />を複製し末尾に新しいタブを追加してください。

_layout.tsx
      // 抜粋
      <Tabs.Screen
        name="two"
        options={{
          title: 'Tab Two',
          tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
        }}
      />
      <Tabs.Screen
        name="wind"
        options={{
          title: 'Tab Wind',
          tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
        }}
      />

アプリのタブバーに新しくTab Windタブが追加されています。

新しくタブが追加された様子の画像

新しく追加されたTab Windをタップしてページを開きます。
以下のようにTailwind CSSでスタイルが当たることを確認します。

新しくページが追加された様子の画像

おわりに

今回は、Expo RouterのプロジェクトにNativeWindを導入し、Tailwind CSSを利用するまでの手順を解説しました。導入手順が少し複雑ではありますが、ユーティリティファーストでアプリ開発を進めることが可能になるので検討する価値があると感じました。

まだまだWeb向けのTailwind CSSよりも情報が少ないですが、React NativeでもTailwind CSSを利用できるのは大きな魅力だと感じました。うまく活用して開発効率を上げていきましょう。

最後まで読んでいただきありがとうございました。

GitHubで編集を提案

Discussion