35
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Create React Appでejectせずにjsx pragma無しのEmotionを使う(TypeScript編)

Last updated at Posted at 2021-05-23

これは何

  • 以下の一連の流れを解決するための記事です
    • CSS in JSの1つであるEmotionは、デフォルトだとjsx pragmaを毎ファイル書かないといけない
      • /** @jsx jsx */とか
      • /** @jsxImportSource @emotion/react */とか
    • 書かずに済むためにはbabelの設定を変える必要がある
    • Create React Appでアプリケーションを作るとejectしないとbabelの設定が変えられない
    • 困ってしまう
  • また、投稿イベント「フロントエンド強化月間 - 開発する上で知っておくべき知見を共有しよう」への記事でもあります

ゴールのイメージ

デフォルトだと、それぞれのtsxファイルで以下のような記述をしないといけませんが

/** @jsxImportSource @emotion/react */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { css, jsx } from '@emotion/react'

以下のようにスッキリさせることができます。

import { css } from '@emotion/react'

また、後ほど説明する@emotion/babel-pluginを入れられるようになることで、見た目の問題だけでなくminifyやデッドコードの解消もできます。

ひとまずCreate React App

自分はyarnを使いつつTypeScript編と銘打っている1ので以下のコマンド。

yarn create react-app my-app --template typescript

現状のビューと、コードは以下のようになっています。

App.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

Emotionと@emotion/babel-pluginのインストール

作業の順番を分かりやすくするため先にEmotionとbabel-pluginを入れておきますが、まだスタイルは書きません。

yarn add @emotion/react
yarn add -D @emotion/babel-plugin

なお、babelの設定のために@emotion/babel-preset-css-propを紹介している記事もありますが、2021年5月現在は基本的に@emotion/babel-pluginを使う方が良いでしょう。

Reactがv17になってからJSXの変換が新しくなり、それに対応しているのは@emotion/babel-pluginだからです。

CRACOのインストールと設定

Create React App Configuration Overrideの略でCRACOだそうです。
頭の中では「クラコ」と読んでいて、可愛らしい名前だなあと勝手に感じています。

yarn add @craco/craco

インストールしたらプロジェクトのルートフォルダにcraco.config.jsという名前のファイルを作って、以下のように記載します。

craco.config.js
module.exports = {
  babel: {
    presets: [
      [
        "@babel/preset-react",
        { runtime: "automatic", importSource: "@emotion/react" },
      ],
    ],
    plugins: ["@emotion/babel-plugin"],
  },
};

詳細な書き方の説明は公式ドキュメントに記載がある通りですが、babel:webpack:の中にオーバーライドしたい設定を書けばOKです。

ちなみに上記のBabelの設定はEmotion公式のCSS Propの説明に記載がある通りです。

その後、npm-scriptsを変更します。

package.json
  "scripts": {
-   "start": "react-scripts start",
+   "start": "craco start",
-   "build": "react-scripts build",
+   "build": "craco build",
-   "test": "react-scripts test",
+   "test": "craco test",
    "eject": "react-scripts eject"
  },

余談:設定をオーバーライドするためのパッケージについて

どんなものがあるのかnpm trendsで調べたところ、一番ダウンロードが多いのはreact-app-rewiredでした。

しかしreact-app-rewiredはCreate React App(以下CRA)の2系にまでしか対応していないのか、動いてくれませんでした。
CRACOはダウンロード数も2位ですし、CRAの4系にも対応しているので最終的にこちらを使っています。

tsconfig.jsonの変更

TypeScriptでEmotionを扱うために、tsconfig.jsonにも少しだけ変更を加えてあげないといけません。
と言ってもCRAで生成されたものに1行追加するだけ。

tsconfig.json
  {
    "compilerOptions": {
      "target": "es5",
      "lib": [
        "dom",
        "dom.iterable",
        "esnext"
      ],
      "allowJs": true,
      "skipLibCheck": true,
      "esModuleInterop": true,
      "allowSyntheticDefaultImports": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "noFallthroughCasesInSwitch": true,
      "module": "esnext",
      "moduleResolution": "node",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "noEmit": true,
-     "jsx": "react-jsx"
+     "jsx": "react-jsx",
+     "jsxImportSource": "@emotion/react"
    },
    "include": [
      "src"
    ]
  }

Emotionを用いてスタイルを変更

やっとスタイルを変更します。
今回は例を示すだけなのでごく簡単な内容を。

App.tsx
- import React from 'react';
  import logo from './logo.svg';
  import './App.css';
+ import { css } from '@emotion/react'

  function App() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.tsx</code> and save to reload.
          </p>
          <a
-           className="App-link"
+           css={appLink}
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }

+ const appLink = css`
+   background-color: #61dafb;
+   border-radius: 8px;
+   color: #212121;
+   font-weight: bold;
+   padding: 20px 40px;
+   text-decoration: none;
+ `
+
  export default App;

まとめ

  • Emotionと@emotion/babel-pluginをインストールする
  • CRACOをインストールする
  • craco.config.jsを作成し、通常.babelrcに書く内容をcraco.config.js内に記載する
  • npm-scriptsをreact-scriptsからcracoへ更新する
  • tsconfig.json"jsxImportSource": "@emotion/react"を追加する
  1. TypeScript編があるならVanillaのJavaScript編があるのかと思いきや、ありません。

35
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?