Motivation
Next.js 14 がリリースされて久しいが、React での CSS in JS ライブラリの一つである Linaria を導入したのでその手順についてまとめた。
Next.js はバージョン 13 から App Router が導入されており、今回も引き続き、その機能を利用する前提での説明となる。
また、意外とハマりポイントであった stylelint の設定にも言及したい。
Pre-condition
開発環境
- 開発環境: Mac/MacOS Sonoma 14.4.1
- npm: 10.2.0
- node: v21.1.0
- VSCode: 1.89.1
手順
Next.js のインストール
詳細は割愛。
create-next-app
などを利用して、普通に最低限のものを next dev
できるまで用意する。
基本セットアップ
linaria を使用できる状態にするための最低限の準備。
以下のパッケージをインストールする。
npm install @linaria/core @linaria/react next-with-linaria @linaria/babel-preset
next.config.js
を以下のように記述する。
/** @type {import('next').NextConfig} */
const withLinaria = require('next-with-linaria');
// 追加で設定をカスタマイズしたい場合は、config に書く
config = {};
module.exports = withLinaria(config);
linaria 公式では、使用するバンドラーによって設定方法が記載されているが、Next.js プロジェクトの場合 next-with-linaria
のパッケージがこの辺りをよしなにこなしてくれるので便利だ。
style のフォーマット
npm install -D stylelint @linaria/postcss-linaria stylelint-order
linaria 公式では、stylelint v14 までの説明しかなく1、そこでは @linaria/stylelint-config-standard-linaria
のパッケージが必要とされている。しかし、stylelint は v15 において大きな変更があり、それに従い多くの rule が deprecated となり、今後は、prettier などのフォーマッタに寄せられるということである。@linaria/stylelint-config-standard-linaria
でもそれら deprecated になった rule が使用されているため、このパッケージは不要となる(というかあるとエラーがすごく出る)。
settings.json
への追記
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
},
"css.validate": false,
"stylelint.validate": ["typescriptreact"]
}
.stylelintrc
を作成し、このような記述を行う
{
"extends": ["stylelint-config-standard"],
"overrides": [
{
"files": ["src/**/*.{jsx,tsx}"]
}
],
"customSyntax": "@linaria/postcss-linaria",
"plugins": ["stylelint-order"],
"rules": {
"order/properties-alphabetical-order": true,
// 以下は好みで。参照: https://stylelint.io/user-guide/rules
"color-hex-length": "long",
"order/properties-alphabetical-order": true,
"declaration-block-no-shorthand-property-overrides": true,
"no-empty-source": null,
"no-descending-specificity": null,
"rule-empty-line-before": "never",
"block-no-empty": null,
"function-no-unknown": null,
"value-keyword-case": null,
"selector-class-pattern": null
}
}
動作確認
ボタンを表示するだけの原始的なコンポーネント
import { styled } from '@linaria/react';
import React from 'react';
export default function Home() {
return (
<main>
<MyButton color="#f9add9">click</MyButton>
</main>
);
}
interface IButton {
color: string;
}
// ※stylelint によるソートがまだ効いていない状態
const MyButton = styled.span<IButton>`
background-color: ${(p) => p.color ?? '#f9add9'};
padding: 20px;
border-radius: 16px;
position: relative;
&:hover {
color: yellow;
border-color: black;
cursor: pointer;
border-style: solid;
}
`;
通常時:
また、上記ソースコードのテンプレートリテラル部分は、VSCode 上でファイルを保存すると、以下のようにソートされる。
// ※stylelint によるソートが効いた状態
const MyButton = styled.span<IButton>`
background-color: ${(p) => p.color ?? '#f9add9'};
border-radius: 16px;
padding: 20px;
position: relative;
&:hover {
border-color: black;
border-style: solid;
color: yellow;
cursor: pointer;
}
`;
セミコロン「;
」が行末に付与されていない時のフォーマットをしてくれない。(prettier 的には行った欲しいのだが。。)