無聊聊Blog

Css in JS: emotion-js 使用及設定

2023-01-20
Css in JS: emotion-js 使用及設定

最近有一個新的頁面需求,想說可以來試試看 Css-in-JS,選擇了很常見的 emotion。 https://github.com/emotion-js/emotion

結果意外的覺得好用,所以想簡單介紹一下使用方式和心得。

emotion 安裝

參考:emotion 文件有詳細安裝步驟說明。

安裝套件 我是使用 React 所以安裝 @emotion/react

npm i @emotion/react

emotion 設定

emotion 提供了 css props,要使用的話需要一些設定。 目前 babel 遇到 jsx 語法,預設會編譯成 React.createElement

<img src="avatar">
// To
React.createElement("img", { src: "avatar.png" });

我們需要告訴 babel,遇到 jsx 語法,使用 emotion 提供的 jsx 方法取代 React.createElement,這樣才能透過 emotion 編譯 css props:

<img src="avatar">
// To
jsx("img", { src: "avatar.png" });

React 17 New JSX Transform

上述是 React 17 以前的版本,在 React 17 後提供了新的功能 Auto JSX Transform (其實 React 16.14 也就是 v16 的最後一版就支援此功能,不過應該是 v17 才正式 release feature?)

https://zh-hant.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

詳細可以去看上述介紹,簡而言之,之前會將 jsx 轉成 React.createElement 因此需要在有使用 jsx 的檔案 宣告 React import React from "react";

啟用了新的 automatic transform jsx 之後,不用再宣告 React:

// 不須宣告 React
function App() {
  return <h1>Hello World</h1>;
}

會編譯成:

// Inserted by a compiler (don't import it yourself!)
import { jsx as _jsx } from "react/jsx-runtime";

function App() {
  return _jsx("h1", { children: "Hello world" });
}

回到 emotion:要使用 emotion 的 css props 有兩種方法設定:

  • Babel Preset
  • JSX Pragma

其中又分為 React 17 前後有不同設定 (因為 auto transform jsx)

Babel Preset

在 .babelrc 設定 因應不同情境,詳細參考文件

{
  "presets": ["@emotion/babel-preset-css-prop"]
}

React 17 (automatic transform jsx)

如果使用 react17 automatic transform jsx feature

{
  "presets": [
    [
      "@babel/preset-react",
      {
        "runtime": "automatic",
        "importSource": "@emotion/react"
      }
    ]
  ]
}

Typescript

如果有使用 typescript

tsconfig.json 須設定

{
  "compilerOptions": {
    // ...
    "jsxImportSource": "@emotion/react"
  }
}

JSX Pragma

第二種,如果你沒辦法設定 babel (例如使用 create-react-app),可以在 file 定義 JSX pragma

/** @jsx jsx */
import { jsx } from "@emotion/react";

這段註解告訴 babel 使用定義的 jsx 取代預設的 React.createElement

React 17 (automatic transform jsx)

如果使用 react17 automatic transform jsx feature

/** @jsxImportSource @emotion/react */

這段註解告訴 babel 從 @emotion/react 來引入 runtime jsx

Css props

設定正確便可以使 Css props 正確套用

import { css } from "@emotion/react";

export default function Item() {
  return (
    <div
      css={css`
        font-weight: bold;
        color: #fff;
      `}
    >
      test
    </div>
  );
}

babel plugin、eslint

另外可以安裝以下幫助開發:

VSCode extension

這個非常重要,Css in JS 基本上只是一串 string,在編寫開發的時候會很痛苦。 因此要在 vscode 安裝 Css-in-JS 相關的 extension,幫助 syntax hightlight 以及 auto-complete。

我是選擇 vscode-styled-components

emotion-js-1

使用心得

emotion 提供了不只一種的 styled api,建議可以去文件看一遍,自己也還不是每種都會使用。

完成設定後,配合 extension,還有 eslint + prettier 設定 個人覺得:使用 Css-in-JS 開發真的非常快速且愉悅!在 JS 裡面寫 Css 意外的非常直覺化。

有些人可能覺得 Css in JS 很醜,不過說真的分開寫 css 又有多少人能寫的乾淨整齊,而且定義 class、 比對 js code 和 css/scss file 也是很痛苦的事。

@emotion 用了非常有感,非常推薦一試。