やってみた理由
Next.js Conf 2022でもお話があったり
t3-appのドキュメントでも紹介されたので手を出してみようかなと。
ただ、cvaをインストールしても、コンポーネントの確認が必要になってくるので、
この機会にstorybookもインストールします(今まで触ったことがない)
手順
-
t3-appの作成
default
フラグをつけて、tailwindcss,next-auth,prisma,trpcを全てインストールする(つけなかったら、何をインストールするか聞かれる)yarn create t3-app --default <app_name>
-
class-variance-authority
をインストールyarn add class-variance-authority
-
class-variance-authorityが使えるか確認してみる
-
Buttonコンポーネントの作成(READMEからREADMEから取ってきた奴)
./src/components/button.tsximport React from "react"; import { cva, type VariantProps } from "class-variance-authority"; // ⚠️ Disclaimer: Use of Tailwind CSS is optional const button = cva(["font-semibold", "border", "rounded"], { variants: { intent: { primary: [ "bg-blue-500", "text-white", "border-transparent", "hover:bg-blue-600", ], // **or** // primary: "bg-blue-500 text-white border-transparent hover:bg-blue-600", secondary: [ "bg-white", "text-gray-800", "border-gray-400", "hover:bg-gray-100", ], }, size: { small: ["text-sm", "py-1", "px-2"], medium: ["text-base", "py-2", "px-4"], }, }, compoundVariants: [ { intent: "primary", size: "medium", class: "uppercase", // **or** if you're a React.js user, `className` may feel more consistent: // className: "uppercase" }, ], defaultVariants: { intent: "primary", size: "medium", }, }); export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof button> {} export const Button: React.FC<ButtonProps> = ({ className, intent, size, ...props }) => <button className={button({ intent, size, className })} {...props} />;
pagesディレクトリで適当にコンポーネントを呼び出す
./src/pages/test.tsximport { Button } from "../components/button"; const Page = () => { return ( <section> <div><Button intent={"primary"}>Test</Button></div> <div><Button intent={"secondary"}>Test</Button></div> </section> ); }; export default Page;
-
Next.jsを起動させて作成したtestページにアクセスしてみる
http://localhost:3000/testyarn dev
こんな感じで表示されます。
作ったコンポーネントをいちいちNext.jsのページに作成して確認したくないので、
storybookをインストールしましょう
-
-
storybookのインストール
yarn dlx storybook init
eslint使ってるか聞かれると思うので、y/nで答えて終了を待つ
(デフォルトではインストールされてないのでn)initコマンドで、package.jsonの書き込みや、
./.storybook/
,./src/stories/
が作成される -
storybookの起動
yarn run storybook
-
storyを作成する
./src/components/Button.stories.tsximport { ComponentStory, ComponentMeta } from "@storybook/react"; import { Button } from "./button"; export default { title: "Example/custom-button", component: Button, argTypes: {}, } as ComponentMeta<typeof Button>; const Template: ComponentStory<typeof Button> = (args) => ( <Button {...args}>Button</Button> ); export const Primary = Template.bind({}); Primary.args = { intent: "primary", size: "medium", }; export const Secondary = Template.bind({}); Secondary.args = { intent: "secondary", };
もう一度storybookを確認する(hotreloadされてるのでコマンド終了してしまった人は再度起動して確認)
普通のボタンだ...
Chromeの検証で確認するとclassは反映されているので、
CSSが読み込まれてないことに気づく...
postcss用のアドオンをインストール
yarn add --dev @storybook/addon-postcss
設定ファイルを編集
./.storybook/main.jsmodule.exports = { stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], addons: [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions", + { + name: "@storybook/addon-postcss", + options: { + postcssLoaderOptions: { + implementation: require("postcss"), + }, + }, + }, ], framework: "@storybook/react", core: { builder: "@storybook/builder-webpack5", }, };
./.storybook/preview.js+ import "../src/styles/globals.css"; export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }
この状態でstorybookを確認すると,,,
-
最後に不要なファイルや設定を削除する(必要な人は)
デフォルトのstoriesフォルダを削除rm -rf ./src/stories/
storiesフォルダをもっと明確に指定
./.storybook/main.jsmodule.exports = { + stories: ["../src/components/**/*.stories.@(js|jsx|ts|tsx)"], addons: [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions", { name: "@storybook/addon-postcss", options: { postcssLoaderOptions: { implementation: require("postcss"), }, }, }, ], framework: "@storybook/react", core: { builder: "@storybook/builder-webpack5", }, };
まとめ
以上、t3-appのプロジェクトにclass-variance-authorityとstorybookを入れる流れでした。
storybookには触れたことがなかったんですが、
class-variance-authorityでよりtailwindcssが使いやすくなりそうだったので導入してみました。
記事では述べていませんが、headlessuiと組み合わせることでより効果を発揮してくれそうです。