これは何
- 以下の一連の流れを解決するための記事です
- CSS in JSの1つであるEmotionは、デフォルトだとjsx pragmaを毎ファイル書かないといけない
-
/** @jsx jsx */
とか -
/** @jsxImportSource @emotion/react */
とか
-
- 書かずに済むためにはbabelの設定を変える必要がある
- Create React Appでアプリケーションを作るとejectしないとbabelの設定が変えられない
- 困ってしまう
- CSS in JSの1つであるEmotionは、デフォルトだとjsx pragmaを毎ファイル書かないといけない
- また、投稿イベント「フロントエンド強化月間 - 開発する上で知っておくべき知見を共有しよう」への記事でもあります
ゴールのイメージ
デフォルトだと、それぞれの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
現状のビューと、コードは以下のようになっています。
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
という名前のファイルを作って、以下のように記載します。
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を変更します。
"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行追加するだけ。
{
"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を用いてスタイルを変更
やっとスタイルを変更します。
今回は例を示すだけなのでごく簡単な内容を。
- 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"
を追加する
-
TypeScript編があるならVanillaのJavaScript編があるのかと思いきや、ありません。 ↩