この記事の概要
Meta 社製の CSS in JS ライブラリである StyleX が登場しました。
2021 年には言及されていたようですが、2023 年 12 月 5 日(現地時間)に一般公開されたみたいです。
普段自分は Vite を使うことが多いので、Vite + StyleX の組み合わせを試してみます。
Vite の準備
まずは作成します。
bun create-vite
React, TypeScript, SWC を選択しました。
StyleX の準備
まずは公式ドキュメントにある通り進めます。
bun i @stylexjs/stylex
続いて、Vite は Rollup を使っているので @stylexjs/rollup-plugin
を入れて動かそうとしましたが、駄目でした。
Issue で議論されていて、Pull Request も作成中なようで、近いうちに公式からサポートされそうではありますが、2023 年 12 月 11 日現在は上手く動きません。
しかし調べたら個人の方がプラグインを作ってくださっていました。
ありがたく使わせていただきます。
bun i -d vite-plugin-stylex
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
+ import styleX from "vite-plugin-stylex";
export default defineConfig({
- plugins: [react()],
+ plugins: [react(), styleX()],
});
これで準備は完了です。
以下は依存関係とバージョンの一覧です。
{
// 省略
"dependencies": {
"@stylexjs/stylex": "^0.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"eslint": "^8.53.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.4",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vite-plugin-stylex": "^0.1.0"
}
}
基本の書き方
stylex
を import した上で
import * as stylex from "@stylexjs/stylex";
stylex.create()
でスタイルを生成して
const styles = stylex.create({
foo: {
color: 'red',
fontSize: '2em'
},
bar: {
backgroundColor: 'blue',
},
});
stylex.props()
で使用します。
{/* 個別に適用 */}
<div {...styles.props(styles.foo)}>foo</div>
<div {...styles.props(styles.bar)}>bar</div>
{/* あわせて適用 */}
<div {...styles.props(styles.foo, styles.bar)}>foo bar</div>
通常のスタイルを書く
create-vite
で生成された App.tsx
にスタイルを当ててみます。
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
+ import * as stylex from "@stylexjs/stylex";
+ const styles = stylex.create({
+ title: {
+ color: "#55c500",
+ },
+ });
function App() {
const [count, setCount] = useState(0);
return (
<>
{/* 省略 */}
<h1 {...stylex.props(styles.title)}>Vite + React</h1>
{/* 省略 */}
</>
);
}
export default App;
before | after |
---|---|
ただ色を変えただけですが、上手く動いています。
以下は出力されたコードです。
<h1 class="App__styles.title x1g81dyc">Vite + React</h1>
.x1g81dyc {
color: rgb(85, 197, 0);
}
少しスタイルを追加してみます。
const styles = stylex.create({
title: {
color: "#55c500",
+ fontSize: "5rem",
+ marginBlock: 0,
},
});
出力されるコードも変わりました。
1 つのプロパティにつき 1 つのクラスが追加されるようです。
<h1 class="App__styles.title x1g81dyc xn7rfii x10im51j">Vite + React</h1>
.x10im51j {
margin-block: 0px;
}
.xn7rfii {
font-size: 5rem;
}
.x1g81dyc {
color: rgb(85, 197, 0);
}
先ほどリンクを貼ったブログ内で atomic class names
と書かれていた作りです。
Tailwind CSS のアプローチと同じような感じです。
state にあわせたスタイルを書く
特別紹介するほどのものでもないかもしれませんが、state にあわせてスタイルを変更するのも問題ないようです。
const styles = stylex.create({
title: {
color: "#55c500",
fontSize: "5rem",
marginBlock: 0,
},
+ button: {
+ backgroundColor: "#ddd",
+ },
+ active: {
+ backgroundColor: "#212121",
+ color: "white",
+ }
});
{/* 中略 */}
<button
onClick={() => setCount((count) => count + 1)}
+ {...stylex.props(count > 0 ? styles.active : styles.button)}
>
count is {count}
</button>
想定通り変化しています。
最後に
まだバージョンは 1 にも満たないので本番適用するのは怖いですが、Meta が出しているなら React との相性は良いはずでは?とも思えます。
期待しつつ引き続き見ておきます。