はじめに
CSS-in-JS(Emotion、styled-components 等)を使用する際、以下のようなタイポに気付けないことがあります。
const style = {
color: "red",
colr: "blue", // タイポだがエラーにならない
};
通常のCSSであれば Stylelint によって未知のプロパティを検出できますが、StylelintではCSS-in-JSを解析するパッケージが非推奨になっています。
本記事では、Emotionを使用している環境で未知のCSSプロパティをエディタ上でインライン検出する方法について試した結果を共有したいと思います。
本記事で検出できるようにしたいこと
eslint-plugin-css の css/no-unknown-property ルールを使用して、オブジェクト形式の CSS の「未知のプロパティ」をエディタ上でインライン検出します。
書き方別の検出方法一覧
| パターン | 必要な設定 | 検出ルール |
|---|---|---|
css={{ }} インライン |
attributes: ["css"] |
css/no-unknown-property |
css({ }) 変数 |
defineFunctions に @emotion/react を追加 |
css/no-unknown-property |
オブジェクト変数 → css 属性 |
attributes: ["css"] |
css/no-unknown-property |
-
attributes: JSX 属性に渡されたオブジェクトを CSS として解釈する -
defineFunctions: 関数呼び出しの引数オブジェクトを CSS として解釈する
Stylelint が利用できない理由
Stylelint で CSS-in-JS を解析するには @stylelint/postcss-css-in-js が必要でしたが、本パッケージは 2023 年 2 月にアーカイブされ、非推奨となっています。
This syntax is deprecated. Please refer to the Stylelint v15 migration guide.
npm でインストールを試みると、以下の警告が表示されます。
npm warn deprecated @stylelint/postcss-css-in-js@0.37.3:
Package no longer supported.
公式情報:
- GitHub: stylelint/postcss-css-in-js — "This repository was archived by the owner on Feb 9, 2023. It is now read-only."
- npm: @stylelint/postcss-css-in-js — "This package has been deprecated"
また、Stylelint v16 との互換性がなく、実行時に以下のエラーが発生します。
TypeError: Cannot read properties of undefined (reading 'stringify')
(そもそも)Stylelint の対応範囲
仮に動作したとしても、Stylelint はテンプレートリテラル形式(css`...`)のみ解析可能であり、オブジェクト形式には対応していません。
// Stylelint 対象(テンプレートリテラル)
const style = css`
color: red;
`;
// Stylelint 対象外(オブジェクト形式)
const style = css({
color: "red",
});
eslint-plugin-css の導入
eslint-plugin-css は、CSS-in-JS のオブジェクト形式を ESLint で検証可能にするプラグインです。
インストール
npm install --save-dev eslint-plugin-css
ESLint 設定
// eslint.config.mjs
import * as cssPlugin from "eslint-plugin-css";
export default [
// 他の設定
cssPlugin.configs["flat/recommended"],
{
settings: {
css: {
target: {
// css={...} 属性を検出対象に指定
attributes: ["css"],
// css({ }) 関数を検出対象に指定
defineFunctions: {
"@emotion/react": ["css"],
},
},
},
},
rules: {
// Emotionのネストセレクタ(&:hover など)を許可するように設定
"css/no-unknown-property": [
"error",
{
ignoreProperties: ["/^&/"], // & で始まるセレクタを許可
},
],
},
},
];
eslint-plugin-css は CSS 標準プロパティのリストと照合してエラーを検出します。
Emotion では &:hover のようなネストセレクタをオブジェクトのキーとして記述できますが、css/no-unknown-property はこれを「プロパティ名」として解釈してしまうため、ignoreProperties で除外する必要があります。
| 構文 | 例 | 対処 |
|---|---|---|
| ネストセレクタ |
&:hover, & > div
|
ignoreProperties: ["/^&/"] |
| CSS変数 | --primary-color |
ignoreProperties: ["/^--/"] |
上記設定例では & で始まるネストセレクタを許可しています。CSS変数も使用する場合は以下のように追加してください。
ignoreProperties: ["/^&/", "/^--/"]
書き方パターン別の詳細
パターン 1: css={{ }}
<div
css={{
color: "red",
colr: "blue", // エラー
}}
>
JSX の css 属性に直接オブジェクトを渡す形式です。インラインで検出されます。
パターン 2: オブジェクト変数
const style = {
color: "red",
colr: "blue", // エラー
};
<div css={style}>
パターン 3: css({ }) 変数
const cssStyle = css({
color: "red",
colr: "blue", // エラー
});
設定: defineFunctions に @emotion/react を追加
css() 関数の引数オブジェクトが自動的に検出されます。
補足:MUI を使用する場合
MUI の sx 属性も同様に検出対象に追加できます。eslint.config.mjs の attributes に "sx" を追加してください。
attributes: ["css", "sx"],
これにより、以下のようなコードでもタイポが検出されます。
import { Box } from "@mui/material";
<Box
sx={{
color: "red",
colr: "blue", // エラー
}}
/>
おわりに
本記事は初心者が調査・検証した内容をまとめたものです。
より適切な方法や他のツールについてご存知の方がいらっしゃいましたら、コメントにてご教示いただけますと幸いです。