Next.js と Emotion でいろいろハマった件 3

Next.js で Emotion を使う場合、JSX Pragma がつけられることで Next.js の <Link> コンポーネントが直下の <a>href をつけてくれなくなるので、その対応をいくつか考えてみました。
また、Next.js や Emotion のバージョンを上げたら起こったことについても書きました。

Version

  • TypeScript 4.0.5
  • Next.js 10.0.1
  • React 17.0.1
  • Emotion 10/11

公式にしっかり書いてありました。

Note: If you’re using emotion’s JSX pragma feature (@jsx jsx), you must use passHref even if you use an <a> tag directly.
next/link | Next.js

.babelrc で presets に @emotion/babel-preset-css-prop を追加している場合 @jsx jsx プラグマが有効です。

公式のとおり、 <Link href={url} passHref> としなくてはいけませんでした。

回避策はあるのか

  1. @emotion/babel-preset-css-prop を使うのをあきらめる

    • <Link> の直下に <a> を置くコンポーネントだけを分離し、そのコンポーネントにはプラグマを書かなければ passHref がなくても href は付与される模様。

    • その代わり css() を使うすべてのファイルに @jsx jsx を書く必要がある。

  2. @emotion/core を使うのをあきらめる

    • 極論ぽいけれど、 @emotion/core を使わなければプラグマフラグも必要ないので、@emotion/css を使う方法がある。

    • css() の結果は string になり、<someElement css={styles}> ではなく <someElement className={styles}> となる。

    • <Global> が使えない...

1.の方法は .tsxjsx と書くのが大変つらいです。
2.の方法はとある企業のブランドサイトを作った時に実際使用しました。割と普通ですが、<Global> が使えないのでグローバルスタイルだけは普通に .css で読み込む必要がありました。

結局どちらもつらいので、今は @emotion/babel-preset-css-prop を presets に加えた上で、以下のような <Link>をラップするコンポーネントを作って凌いでいます。

type Props = { href: string | URL, as?: string}
const AppLink: React.FC<Props> = props => {
  return <Link href={props.href} as={props.as} passHref>
    <a>{props.children}<a>
  </Link>
}
export default AppLink;

React 17 にしたら @jsx jsx でエラーが出るようになった

Next.js が 10 になったので早速プロジェクトをアップデートし、合わせて React が 17 になったら JSX プラグマで以下のようなエラーが出ました。

/** @jsx jsx */
import { jsx, css } from '@emotion/react'

SyntaxError: pragma and pragmaFrag cannot be set when runtime is automatic.

解決策

jsx ランタイムのオプションが classic から automatic に変わったかららしいです。 公式の通り /** @jsxImportSource @emotion/react */ (Emotion 10 の場合は /** @jsxImportSource @emotion/core */) を使う。

If you are using a zero-config tool with automatic detection of which runtime (classic vs. automatic) should be used and you are already using a React version that has the new JSX runtimes (hence runtime: 'automatic' being configured automatically for you) such as Create React App 4 then /** @jsx jsx */ pragma might not work and you should use /** @jsxImportSource @emotion/react */ instead.
Emotion - The css Prop

Emotion 11 になったら @emotion/core がなくなった

Emotion 11 では多くのパッケージの名前が変更されました。

@emotion/core@emotion/react に変わったそうです。

Emotion - Emotion 11

まとめ

自分が勉強するはやさよりも使用しているパッケージの更新の方がはやいので大変。

関連記事
unimoku

Web サイトの制作、運営とアプリケーションのフロントエンド開発などをやっています。主に使うのはTypeScript、JavaScript、PHP、C/C++。特にTypeScriptが好きです。