はじめに
僕は個人開発や副業先で技術選定をする際は、専らTailwindCSSを使っています。
.cssファイルと.tsxファイルを交互に見たり、コードが長くなったりせず、爆速で開発できるのが気持ちいいですよね。
最近はjitモードも追加されて、痒い所に手が届くようになった、TailwindCSSですが、メリットはそのままにCSS in JSとして扱える、twin.macroの使い方についてまとめたいと思います。
twin.macroがどんな感じで使えるかは最後の方で紹介してますので、気になる方はそこだけでもみていって頂けると嬉しいです!
この記事で作成したプロジェクトをもとにセットアップを行いますので、よろしければ、こちらの記事も覗いていただけると嬉しいです。
( ちなみにcreate react appではなくviteを使っています。もし使ったことない方は爆速vite試してみてください。)
TailwindCSSインストール
まずは、パッケージをインストールしましょう。
yarn add tailwindcss postcss autoprefixer --dev
以下のコマンドでtailwind.config.js
とpostcss.config.js
を生成します。
yarn tailwindcss init -p
次に、tailwind.config.js
を以下のように書き換えましょう
/** @type {import('tailwindcss').Config} */
module.exports = {
mode: 'jit',
content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
theme: {
extend: {},
},
plugins: [],
}
そして、src/index.cssをこのように変更してください。
( デフォルトの内容は全消ししちゃって大丈夫です。 )
@tailwind base;
@tailwind components;
@tailwind utilities;
最後にsrc/main.tsxでTailwindCSSを読み込んであげればOKです。
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import 'tailwindcss/tailwind.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
)
これでTailwindCSSが使えるので、試しにsrc/App.tsx
をこのように変更してみます。
// .....
function App() {
const [count, setCount] = useState(0)
return (
Hello Vite + React!
こんな感じでいつもの画面が表示され、className
を指定した部分が変化していれば完璧です!
HelloTailwindCSS
twin.macroセットアップ
twin.macroインストール
TailwindCSSが使えるようになったので、次はこれをCSS in JSとして扱えるtwin.macroをインストールしていきます。
yarn add @emotion/react @emotion/styled
yarn add --dev twin.macro @emotion/babel-plugin-jsx-pragmatic babel-plugin-macros tailwindcss -D
GlobalStyle適用
次にtwin.macroが用意してくれてるGlobalStyleを適用するようにしましょう。
まずはsrc/GlobalStyles.tsxを新規に作成します。
import React from 'react'
import { css, Global } from '@emotion/react'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'
const customStyles = css({
body: {
WebkitTapHighlightColor: theme`colors.purple.500`,
...tw`antialiased`,
// グローバルスタイルをカスタマイズしたいなら、ここに追記していく
},
})
const GlobalStyles = () => (
<>
>
)
export default GlobalStyles
次に、src/main.tsxに作成したGlobalStyleを読み込むようにしましょう。
src/index.cssは使わなくなるので消しちゃって大丈夫です。
すでにsrc/index.cssにグローバルスタイルを書いてる場合はGlobalStyleに移行すると良いです。
import React from 'react'
import ReactDOM from 'react-dom/client'
import GlobalStyles from './GlobalStyles'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
)
viteにプラグインを追加
vite.config.jsを以下のように編集し、プラグインを追加しましょう
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({
babel: {
plugins: [
'babel-plugin-macros',
[
'@emotion/babel-plugin-jsx-pragmatic',
{
export: 'jsx',
import: '__cssprop',
module: '@emotion/react',
},
],
[
'@babel/plugin-transform-react-jsx',
{ pragma: '__cssprop' },
'twin.macro',
],
],
},
}),
],
esbuild: {
logOverride: { 'this-is-undefined-in-esm': 'silent' }
},
});
Typescript設定
Typescriptを使ってない人はスキップしてOKです。
Typescriptを使っていて、@types/react
をインストールしてない方はインストールしてください。
src/types/twin.d.tsを新規で作成し、以下の内容を記載します。
( 他のディレクトリに型定義ファイルをまとめてる方はそちらのディレクトリに作成してください。)
import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import { CSSInterpolation } from '@emotion/serialize'
import styledImport from '@emotion/styled'
declare module 'twin.macro' {
// The styled and css imports
const styled: typeof styledImport
const css: typeof cssImport
}
declare module 'react' {
// The css prop
interface HTMLAttributes extends DOMAttributes {
css?: CSSInterpolation
tw?: string
}
// The inline svg css prop
interface SVGProps extends SVGProps {
css?: CSSInterpolation
tw?: string
}
}
最後にtsconfig.jsonに1行追加して設定は完了です。
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
TailwindCSS + twin.macroを使ってみる
まずは、classNameで指定していたTailwindCSSをtwin.macroを使ってCSS in JSに書き換えてみましょう。
src/App.tsxを以下のように書き換えてください。
import { useState } from 'react'
import logo from './logo.svg'
import './App.css'
import tw from "twin.macro"
function App() {
const [count, setCount] = useState(0)
return (
Hello Vite + React!
このようにjsxのcss
プロパティにtw
メソッドを使って、TailwindCSSを当てることができます。
次に、color
引数によってchildren
のテキストカラーを変更させるTextコンポーネントについて考えてみます。
import tw, { TwStyle } from "twin.macro";
type Color = "blue" | "red" | "yellow";
type TextProp = {
color: Color;
children: React.ReactNode;
};
const colorize: {
[key in Color]: TwStyle;
} = {
blue: tw`text-blue-600`,
red: tw`text-red-600`,
yellow: tw`text-yellow-600`,
};
const Text = (prop: TextProp) => {
return { prop.children }
};
こんな感じでTailwindCSSをCSS in JSを用いて利用することで、typescriptとの相性も抜群に良くなります。
また、以下のようにemotion
と組み合わせて使ったり、
import { css } from "emotion/css";
import tw from "twin.macro";
const textStyle = css`
${tw`text-red-500`}
`;
styledコンポーネントチックに記述したり、
import tw from "twin.macro"
const Button = tw.button`
bg-primary-200
cursor-pointer
`;
styledコンポーネントで引数を設けたりできます。
import tw, { styled } from "twin.macro";
const buttonBaseStyle = tw`bg-primary-600 text-white`
const Button = styled.button( ({ large }: { large?: boolean }) =>
[
buttonBaseStyle,
large ? tw`text-xl` : tw`text-base`,
]
)
僕はtw
メソッドだけでなんとかなる場合が多いので、まずはライトに爆速Tailwind開発始めてみてはいかがでしょうか。