Gatsby & TypeScript の個人ブログを Tailwind から Chakra UI に入門しつつ移行したログ
個人的なブログ https://blog.hppd.dev のブランチを切って Chakra UI に入門しつつ、よさげだったら Tailwind CSS からの移行も視野に入れる よさげなので移行する。
Chakra UI is a simple, modular and accessible component library that gives you the building blocks you need to build your React applications.
Reactでアプリを作るのに便利なやつを提供するシンプルでモジュラーでアクセシブルなコンポーネントライブラリ。思いっきしブログなんかで使おうとしているが広義のアプリということにしてほしい。
ブログには大仰すぎると感じたらTailwindを使い続ければよい (改善の余地がありそうということは前々から思っている)。
作業用BGM
とりあえず適当に Get Started を押す。必要なパッケージを入れる。
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
framer-motion
はなんかアニメーションライブラリっぽい。
そしてEmotionに依存している。もともとtwin.macroを使ってTailwindとEmotion併用してたが、Emotionのv11がいつの間にか出てるのでアップグレードしておく。
Emotion 11でパッケージが色々とリネームされている。
Most of this renaming can be done automatically via a codemod by running the @emotion/pkg-renaming rule from @emotion/eslint-plugin with --fix over your codebase.
@emotion/eslint-plugin
を入れてパッケージリネーム用の設定を走らせればいいらしい。このeslint-plugin自体も eslint-plugin-emotion
という名前から変更されている。
eslintrc.json
にこれを追加して eslint --fix
でOK。うっかり @emotion/core
からインポートしたりしそうなので設定はしばらく残しておく。
"plugins": [
"@emotion"
],
"rules": {
"@emotion/pkg-renaming": "error"
}
Chakra UI を使うにはアプリを <ChakraProvider></ChakraProvider>
で囲む必要があるのだが、Gatsbyの場合はプラグインを入れれば全部やってくれるので丸投げすればおk。
思想でも読んどく。訳は超意訳。
Chakra UI is established on principles that keep its components fairly consistent. Understanding these concepts will help you better contribute to Chakra UI.
Chakra UI はコンポーネントに矛盾がないよう保つ原則にのっとっているよ。これを読むとコントリビュートするとき役立つよ。
矛盾って思想に反してるってことか?
Our goal is to design simple, composable components that cater to real-life UI design problems. In order to do that, we developed a set of principles that help us always be on that path.
おれたちのゴールは現実のUIデザインの問題にこたえられるシンプルでコンポーザブルなコンポーネントをデザインすることだ。その目的から外れないように行動指針のまとめを作って発展させてきた。
composableは「構成可能な」って訳されるけどまずその日本語の意味がよくわからん。どうでもいいけど「日本語は漢字があるから初見の単語の意味も字面から捉えられる」とか言ってる人間にこれを叩きつけたい。個人的にはパーツを組み合わせて大きなものを組み上げられるみたいな感じだと勝手に解釈してる。
- Style Props: All component styles can be overriden or extended via style props to reduce the use of css prop or styled(). Compose new components from Box.
propsを使ってスタイルを上書きしたり拡張したりできるらしい。Box から新しいコンポーネントを構成するっていうのは進めないとよくわからん。
- Simplicity: Strive to keep the component API fairly simple and show real world scenarios of using the component.
コンポーネントのAPIをシンプルに保ち、現実での使い方を示す。
- Composition: Break down components into smaller parts with minimal props to keep complexity low, and compose them together. This will ensure that the styles and functionality are flexible and extensible.
/compos(e|able|ition)/ についての解説あるな。コンポーネントをより小さいパーツごとに分解してpropsを減らすことで複雑さを抑え、そんでそれらのパーツを組み合わせて使う。こうするとスタイルと機能の柔軟性と拡張性が上がる。
- Accessibility: When creating a component, keep accessibility top of mind. This includes keyboard navigation, focus management, color contrast, voice over, and the correct aria-* attributes.
アクセシビリティ第一。キーボードナビゲーション、フォーカス管理、色のコントラスト、音声読み上げ、aria-*属性。
- Dark Mode: Make components dark mode compatible. Use our
ColorModeProvider
component anduseColorMode
hook to handle styling. Learn more about dark mode.
コンポーネントはダークモードでも使える。カラーモード取るのに React Hooks が使える。
- Naming Props: We all know naming is the hardest thing in this industry. Generally, ensure a prop name is indicative of what it does. Boolean props should be named using auxiliary verbs such as
does
,has
,is
andshould
. For example,Button
usesisDisabled
,isLoading
, etc.
名前付けって作業が一番大変。一般的にpropの名前はそれが何をするのか明確になっている。真偽値なら does
has
is
should
みたいな助動詞を使う。Button
には isDisabled
isLoading
みたいなのがある。
まあよくリーダブルコードとかで言われるのと同じ感じ。
タイムリーなことに UIT Meetup で Chakra UI のLTが行われている。観る
YouTubeのvideoIDが不正です- Pure TypeScript なので自然な補完が出る
- デフォルトのBreakpointsがem指定
- Stack Flexぽいやつ
作業用BGM
Container 読む。
Containers are used to constrain a content's width to the current breakpoint, while keeping it fluid.
By default, it sets the
max-width
of the content to 60 characters (60ch
) but you can customize this by passing custommaxWidth
values or changing the container size tokens defined intheme.sizes.container
.
Tailwindと挙動が違う?Tailwindの container
は1個下のブレークポイントの幅になるのだが、ChakraUIのデフォルトだと 60ch
固定なのか?
そういえば gatsby-config.js
編集するの忘れてた。@chakra-ui/gatsby-plugin
を追加してない。
Box
もっとも抽象的。単に div
を描画する。
そこそこ理解してきた。TailwindはVSCode拡張を入れないと補完が効かなくてつらいがChakra UIは普通に効いてくれるのでうれしい。
wrap="wrap-reverse"
みたいな文字列もちゃんと文字列リテラルのUnionが取られている。TypeScriptわかってる。
おお…いい感じじゃん?
Stack
の divider
が地味に便利。並べるやつの隙間に線引こうとするとどうしても :first-child
とかが必要になりがちだがこいつならまったく不要。最高。
コード
export const PostList: React.FC<PostListProps> = ({ nodes }) => (
<VStack divider={<StackDivider />} spacing="1.5rem">
{nodes.map(
({ excerpt, fields, frontmatter }) =>
frontmatter?.tags &&
fields?.path && (
<PostLink
path={fields.path}
yyyymmdd={fields.yyyymmdd}
title={frontmatter.title}
tags={frontmatter.tags.filter(isntNull)}
key={fields.path}
excerpt={excerpt}
/>
)
)}
</VStack>
);
export const PostLink: React.VFC<PostLinkProps> = ({
excerpt,
path,
tags,
title,
yyyymmdd,
}) => (
<Box as="article" px=".5rem">
<Wrap spacing=".5rem" direction="row" wrap="wrap">
{yyyymmdd && (
<WrapItem>
<PostDate path={yyyymmdd} />
</WrapItem>
)}
<WrapItem>
<TagList tags={tags} />
</WrapItem>
</Wrap>
<Heading my=".5rem">
<Hyper
to={`/${path}`}
css={css`
font-feature-settings: "palt";
`}
>
{title}
</Hyper>
</Heading>
<Text color="gray.600">{excerpt}</Text>
</Box>
);
既存の Box
とかをコンポーネントにまとめたいとき、型を React.FC<React.ComponentProps<typeof Box>>
とするのはあまりにも面倒だ。しかしそんな時のために Chakra UI にはくっそ便利な ChakraComponent<E, P>
型が用意されている。E
に 'div'
などの要素名を入れ、P
にいつもどおりのPropsの型を入れるとそのとおりのPropsを受け取るコンポーネントの型になる。
うそかも。props
の型が Box
と合わない。
呪術廻戦観てた
各種コンポーネントをChakraっぽいコンポジション的な感じに組み替えている。すごくわかりやすくなってるというか今までアンチパターン踏んでたっぽい?
お久しぶりです.ついにテーマをカスタマイズする刻 (とき) がやってきた.
によればTo use customize the theme in your Gatsby site, you can shadow the plugin’s
src/@chakra-ui/gatsby-plugin/theme.js
file with your own theme:
だそう.
要するに src/@chakra-ui/gatsby-plugin/theme.js
でテーマオブジェクトを export default
すればいいらしい.Gatsbyプラグイン系だと gatsby-config.js
でこねこねさせるのが多いのでわりと珍しいと思った.珍しすぎて node_modules/@chakra-ui/gatsby-plugin/src/theme.js
を直接上書きさせるのかと勘違いしてた.
こんな感じ.こういう奴は基本的にTypeScript入れると爆発して死ぬのでJavaScriptで書くが,extendTheme
で引数に型がちゃんとついてるので補完は効く (エラーは出ない).
import { extendTheme } from "@chakra-ui/react";
const theme = extendTheme({
config: { initialColorMode: "dark" },
colors: {
gray: {
50: "#F9F9FD",
100: "#F0F1F8",
200: "#E7E6F1",
300: "#D2D3E3",
400: "#ABAAC3",
500: "#7F7C9A",
600: "#55516A",
700: "#37344A",
800: "#211E2D",
},
purple: { 990: "#1a1723" },
},
components: {
Link: {
baseStyle: {
color: "pink.400",
},
},
},
});
export default theme;
感想,ChakraUIはたのしい.
- 自然にTSXで型がつくのでたのしい
- 普通にカスタマイズ性もそこそこあるのでたのしい
- CSS modulesに戻すときとかつらそう 知らんけど
- 使いやすいコンポーネント設計の参考になった