【Next.js & TypeScript】Emotionの導入が大変だったので手順をまとめておく
CSS in JSとして後発だけありEmotionは使い勝手いいですよね。Material UIがv5からEmotionを利用している影響もあるのか、React版の@emotion/reactはnpmダウンロード数の伸びがすごいです。
@emotion/css vs @emotion/react vs @emotion/styled vs styled-components
(赤が Styled Component、他が Emotion の主要ライブラリ)
ただ、EmotionをNext.js & TypeScriptに導入するのはそこそこ面倒です。ハマりどころも結構多いので手順をこの記事にまとめておきます。Next.js & TypeScriptでEmotionを使おうと思っている方の参考になれば嬉しいです。
筆者の環境
- Next.js v11.1.2
- React v17.0.2
- Emotion v11.4.1
- @emotion/react を使用
- TypeScript v4.4.3
Emotion 導入済みのソースコード
この記事の設定をすべて済ませたコードをGithubに上げています。
※Next.js公式にもEmotionの例があるのですが、そちらはTypeScriptではないので設定が違います。
EmotionをNext.js & TypeScriptに導入する手順
それでは詳しい手順を見ていきましょう。
まず、Emotionのパッケージと、Emotionのbabel用プラグインを入れます。
yarn add @emotion/react @emotion/babel-plugin
そしてEmotionを読み込んで使うわけですが、そのまま下記のようにしても利用できません。
import { css } from "@emotion/react"
これはEmotionが以下のようにタグやコンポーネントにcss prop
を使うため、JSX→JavaScriptのコンパイル設定を調整する必要があるからです。
<div css={{ marginTop: "10px" }}>
<p>テキスト</p>
</div>
JSXのコンパイルを調整するには2つの方法があります。
- JSXプラグマと言われるディレクティブを書く方法
- BabelのConfigを設定する方法(おすすめ)
以下で詳しく見ていきましょう。
JSXプラグマを使う方法
JSXプラグマというディレクティブを追記する方法です。具体的には下記のようなプラグマ(/** 〜〜 */
)をモジュール読み込みの前に追加します。
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react"
この方法はこれだけでオッケーなので簡単なのですが、すべてのコンポーネントファイルに対してこの記述をするのは冗長な感じがしますよね。
そこでおすすめなのがBabelのConfigを設定する方法です。babelのconfigファイルを追加する必要はありますが、一度設定すればプラグマの記述は必要なくなります。
BabelのConfigを設定する方法(おすすめ)
手順ですが、Next.jsのトップディレクトリで .babelrcを作成します。
vi .babelrc
そして下記内容で保存します。
{
"presets": [
[
"next/babel",
{
"preset-react": {
"runtime": "automatic",
"importSource": "@emotion/react"
}
}
]
],
"plugins": ["@emotion/babel-plugin"]
}
これだけです。簡単ですね。
ちなみに、以前はこの方法を使うと以下のようなReactのshorthand syntax(<> </>
)が使えなくなる問題が発生していたのですが、今は解消されておりました。
return (
<>
<Hoge />
</>
)
TypeScript の型定義ファイルを読み込む
TypeScript用にEmotionの型定義ファイルが必要です。
Emotionの型定義ファイルは @emotion/react/types/css-prop
にあるのですが、tsconfig.json
を使って読み込むのがいいでしょう。
tsconfig.json
のcompilerOptions
にtypes
を追加して Emotion の型定義ファイルを指定します。
{
"compilerOptions": {
〜
"types": ["@emotion/react/types/css-prop"],
〜
}
〜
}
ちなみにネット上ではnext-env.d.ts
に以下を追加する方法も紹介されてたりしますが、筆者の環境だとビルドの際にnext-env.d.ts
はリセットされるのでこの方法は使えませんでした。
/// <reference types="@emotion/react/types/css-prop" />
ただ、additional.d.ts
など別ファイルを作ってそちらに上記を記述し、tsconfig.json
のinclude
でadditional.d.ts
を追加するというのも可能ではあると思います。
以上でEmotionがNext.js & TypeScriptで動作するようになったと思います。
しかしEmotionを導入したことでいくつか注意点があるので確認しておきましょう。
Emotion導入後の細かい注意点
Linkコンポーネントが正しく動作しなくなる
Emotionはcss prop
を使うためにJSXのコンパイル設定をいじっていることをすでに書きました。
その副作用だと思うのですが、Next.js標準のLinkコンポーネントにおいて、aタグにcss prop
がある場合、aタグのhref属性が自動生成されない問題が発生します。
なので、下記のように Linkコンポーネントに毎回passHref
を追加するか、
<Link href="/hoge" passHref>
<a css={foo}>リンクボタン</a>
</Link>
下記のようにLinkコンポーネントをラップしたコンポーネントを用意する必要があります。私はこちらの方法で対応しています。
import Link from "next/link"
type Props = {
children: React.ReactNode
href: string | URL
as?: string
}
export default function MyLink(props: Props) {
return (
<Link href={props.href} as={props.as} passHref>
{props.children}
</Link>
)
}
SSR するなら@emotion/css は非推奨
Emotionの主要なライブラリは@emotion/css
、@emotion/react
、@emotion/styled
がありますが、SSRをする場合は@emotion/css
は非推奨となっています。
@emotion/css
はcss prop
を使わず、ReactのclassName
を使う方法です。css prop
を使わないのでJSXコンパイルの設定変更が不要というメリットはあるのですが、SSRにおいてpre-rendering時にCSSが読み込まれなくなる現象が発生します。
なので、SSRを使う場合は@emotion/react
、@emotion/styled
のどちらかを使用することになります。
シンタックスハイライト、入力補完は Styled Component のものを入れる
コードのハイライトや入力補完はEmotion専用のものはほとんどないと思います。
ただ、Styled Componentのものを利用すれば問題なく対応できる場合が多いと思います。
VSCodeであればvscode-styled-components
を使えばいいでしょう。tsxファイル内でも以下のように見やすく表示されますし補完もしてくれます。
まとめ
Emotionは実際に使ってみるととても便利なのですが導入時にハマりどころが多いです。
これもcss prop
というEmotionの独自機能が原因なのですが、この機能自体がEmotionが便利な理由でもあるのでしょうがない面もあるかなと思います。
Emotionの初期設定を済ませたコードはGithubに置いてあります。それではみなさんも良いEmotionライフをお過ごしください。
Discussion