CSSライブラリを goober から TailwindCSS に移行した

 / #nextjs #typescript #tailwindcss

Next.js v13 とまだベータ機能である app dir をこのブログにも適用させようとした際に、ドキュメントに CSS in JS が Server Components (以下 SC)で非対応という事を見落として、下画像の様な goober 関連のエラーに遭遇した。

image

Warning: CSS-in-JS is currently not supported in Server Components.

Styling: CSS-in-JS | Next.js

ただし、styled-jsxstyled-componentsuse client と明記してさらに適切な処理を新たに加えれば Client Components (以下 CC)で動くとも書いてある。CSS はすべてのページに渡っている以上は、すべてのページが CC で動作するという事になり、それでは Next.js app dir を試す理由がなくなるので、TailwindCSS に移行することにした。(CSS in JS はoriverk.devの方でも使っている。)

同様の処理で goober やその他の明記されていない CSS in JS ライブラリが動くかどうは別レポジトリで試したい。

goober

※メモ書き

コード

goober 使用下ではこんな感じになっていた。Next.js v13 app dir では v12 までの _app.tsx_document.tsx が非対応なので、エラーを起こして当然ではある。

src/styles/goober.js
import { createGlobalStyles } from 'goober/global'
export const GlobalStyles = createGlobalStyles`
:root {
--color-miku: #00e1ee;
}
src/pages/_app.tsx
import { setup } from 'goober'
setup(React.createElement, prefix)
export default function MyApp({ Component, pageProps}: AppProps) {
return (
<>
<Head />
<GlobalStyles />
<Component {...pageProps} />
</>
)
}
src/pages/_document.tsx
import { extractCss } from "goober"
export default class MyDocument extends Document<{ css: string }> {
static async getInitialProps({ renderPage }: DocumentContext) {
const page = await renderPage()
// Extrach the css for each page render
const css = extractCss()
return { ...page, css }
}
render() {
return (
<Html>
<Head>
<style
id={'_goober'}
// And defined it in here
dangerouslySetInnerHTML={{ __html: ' ' + this.props.css }}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
src/components/markdown/codeblock/copy-button.tsx
import { styled } from 'goober'
interface PasssedProps {
code: string
}
interface Props extends PasssedProps {
className?: string
}
const Component = ({ className, code }: Props) => (
<button className={className}>{code}</button>
)
const StyledComponent = styled(Component)`
background: var(--color-miku);
font-weight: bold;
padding: 0.2rem 0.5rem;
`
const ContainerComponent: React.FC<PasssedProps> = (props) => <StyledComponent {...props} />
export const Button = ContainerComponent

TailwindCSS

基本的にInstall Tailwind CSS with Next.js - Tailwind CSSに倣って導入した。

npm i -D tailwindcss postcss autoprefixer
npm i @heroicons/react
npx tailwindcss init -p

また、マークダウン箇所は基本的に@tailwindcss/typography - Tailwind CSSを利用し、typography で対応しきれない箇所用の CSS には SCSS を利用することにした。

npm i -D @tailwindcss/typography sass

CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--color-miku: #00e1ee;
}
.markdown {
h2 > a::before {
/* Safari 用のフォールバック */
content: '## ';
/* 読み上げ等に対しては空文字として認識させる */
content: '## ' / '';
}
}
}

markdown list

image

::before::after の疑似要素や置換要素 content などの使い方は、jxck 氏のblog.jxck.ioを勝手に参考にさせてもらいました。

また、CSS の :has():is():not()といった疑似要素をはじめて使いましたが、結構便利でした。

figure:has(img), :not(figure) > img {
border: 1px solid gray;
}
:is(figure) > img {
border: none;
}
figcaption {
text-align: center;
}

Prettier for TailwindCSS

TailwindCSS 推奨のクラス名に並べ替えるための Pretteir プラグインを利用した。

npm i -D prettier prettier-plugin-tailwindcss

ESLint や Prettier の他のプラグインなどと違って、こちらは何の設定もなく動いた。

It works seamlessly with custom Tailwind configurations, and because it’s just a Prettier plugin, it works anywhere Prettier works — including every popular editor and IDE, and of course on the command line.

Automatic Class Sorting with Prettier - Tailwind CSS

参照