Linaria のセットアップ for Next.js 14

## Motivation

Next.js 14 がリリースされて久しいが、React での CSS in JS ライブラリの一つである [Linaria](https://github.com/callstack/linaria) を導入したのでその手順についてまとめた。
Next.js はバージョン 13 から [App Router](https://nextjs.org/docs/app) が導入されており、今回も引き続き、その機能を利用する前提での説明となる。
また、意外とハマりポイントであった 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` できるまで用意する。

https://nextjs.org/docs/app/api-reference/create-next-app

### 基本セットアップ

linaria を使用できる状態にするための最低限の準備。
以下のパッケージをインストールする。

```sh
npm install @linaria/core @linaria/react next-with-linaria @linaria/babel-preset
```

`next.config.js` を以下のように記述する。

```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 のフォーマット

```sh
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 が使用されているため、このパッケージは不要となる（というかあるとエラーがすごく出る）。

[^1]: https://github.com/callstack/linaria/blob/master/docs/LINTING.md#stylelint-14

`settings.json` への追記

```json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": "explicit"
  },
  "css.validate": false,
  "stylelint.validate": ["typescriptreact"]
}
```

`.stylelintrc` を作成し、このような記述を行う

```json
{
  "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
  }
}
```

### 動作確認

ボタンを表示するだけの原始的なコンポーネント

```page.tsx
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;
  }
`;

```

通常時:

![スクリーンショット 2024-05-20 23.17.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671630/51f8627c-bfc6-ca25-9ab9-55c027ee1d8a.png)

カーソルホバー時:
![スクリーンショット 2024-05-20 23.18.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671630/fdc26be8-33d5-a25e-2bc6-3a23e55ecfe7.png)


また、上記ソースコードのテンプレートリテラル部分は、VSCode 上でファイルを保存すると、以下のようにソートされる。

```tsx
//　※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;
  }
`;
```

:::note warn
セミコロン「`;`」が行末に付与されていない時のフォーマットをしてくれない。（prettier 的には行った欲しいのだが。。）
:::