一足先にStorybook8の世界を覗いてみる

## はじめに
現在Storybookのバージョン８がalpha版としてリリースされています。
まだ、安定して利用できるバージョンではないですが、バージョン7のコードを書く上であらかじめ気をつけておきたい点を把握したり、より快適で楽しい新機能を体験するために、足を踏み入れてみます。

この記事では、バージョン８へのアップデート方法と、バージョン８での変更を確認していきます。

:::note warn
この記事はStorybookのバージョン8.0.0-alpha4時点での内容になります。今後のバージョンアップで内容が変更されることは大いに考えられるので注意してください。
:::

## バージョンアップ
Storybookバージョン８には以下のようなコマンドであげます。
```sh
npx storybook@next upgrade --prerelease
```
バージョン7の時と違って、コードベースの大きな変更は必要ありませんでした。

## 変更
Storybook8までの[変更履歴](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.prerelease.md)や[マイグレーションガイド](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-7x-to-800)を参考に記述します。

### 利用環境
Nodejsの最低バージョンが18になりました。利用する際はNodejsバージョン18以降のものを使うようにしてください。
Nextjsの13.5未満のバージョンへのサポートがされなくなりました。
Angularの15未満のバージョンがサポートされなくなりました。

### actionのモック
Storybookではデフォルトで以下のような初期設定が行われます。
```tsx:preview.ts
const preview: Preview = {
  parameters: { 
    actions: { argTypesRegex: "^on[A-Z].*" },
  },
};

export default preview;
```
Storybookは、ここで設定している`actions`の`argTypesRegex`に一致する関数がpropsとして渡されるコンポーネントを扱う場合、その関数を自動で`spy`するようになります。
これによって以下のように、簡単にテストを記述できるのでとても便利でした。
```tsx
import type { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';

import { Button } from './Button';

export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
  play: async ({ args, canvasElement }) => {
    await userEvent.click(within(canvasElement).getByRole('button'));
    // onClickに何の設定もせずに`toHaveBeenCalled`を確認できる！
    await expect(args.onClick).toHaveBeenCalled();
  },
};
```
しかし、この機能にはいくつか問題がありました。それは、コンポーネントを解析するライブラリ(`decgen`)がない時に動作しないことでした。
これがない環境でレンダリングできるようにすることでテストの幅が広がりますし、解析が必要な他の場面があっても遅延読み込みが可能になり、パフォーマンスが向上します。
そのため、今後はこのような暗黙的に対象を`spy`するのはやめて`@storybook/test`を用いて明示的に`spy`させる用になります。

```tsx
import type { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';

import { Button } from './Button';

export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
    onButton: fn(),
  },
  play: async ({ args, canvasElement }) => {
    await userEvent.click(within(canvasElement).getByRole('button'));
    // onClickに何の設定もせずに`toHaveBeenCalled`を確認できる！
    await expect(args.onClick).toHaveBeenCalled();
  },
};
```
(今のバージョンだとまだ自動で`spy`されてしまいました。)

### タイトルの自動設定
Storybook7からStoryを生成するパスを自動生成できるようになりました。
以下の例だと`Button`のStoryは`EXAMPLE/Button`というパスに生成されています。
![スクリーンショット 2023-12-24 12.58.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/19d905ed-afe9-7904-b0d3-c2c7b4ca2f42.png)
これは、`example/Button.stories.tsx`のStoryを自動生成した時に生成される場所です。
このようなパスの自動生成には`example/Form.Button.stories.tsx`のようなStoryを生成した時に`EXAMPLE/Form`というパスに生成されるというようなバグがありました。
今後は`.stories`前の`EXAMPLE/Form.Button`に生成されます。

### react-docgen
Storybookでは`react-docgen-typescript`を用いてコンポーネントのpropsなどのメタ情報を解析しています。
バージョン8.0はそのデフォルトの機能を`react-docgen`にしました。これによって解析効率があがり、起動時間の大幅な短縮を図っています。
この変更によって基本的なTypeScript構造しか変更できなくなったので、元の設定にしたい場合は設定を追加してください。
```ts:main.ts
typescript: {
  reactDocgen: 'react-docgen-typescript',
}
```

### マネージャーUI
マネージャーUIは青色で囲んだ部分です。
![スクリーンショット 2023-12-24 12.23.41 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/84f576ab-2073-e6ef-82d6-320aa1a2efeb.png)
この部分はこれまで、Reactのバージョン16で作成されていましたが、このバージョンアップでReact18を用いて作成したものになりました。

### `addon.setConfig`
StorybookのUIを設定する[`setConfig`](https://storybook.js.org/docs/addons/addons-api#addonssetconfigconfig)の一部が変更されました。

Storyの一覧を表示しているナビゲーションを出すかどうかを決める`showNav`が`navSize`になります。出すかどうかではなく、サイズを数値で指定するようにします。

アドオンの設定を表示するパネルを出すかどうかを決める`showPanel`が`bottomPanelHeight`と`rightPanelWidth`になります。同じく数値で指定するようになります。

`fullScreen`はこれらを組み合わせて表示できるので、サポートされなくなりました。

### `@storybook/components`
`@storybook/components`はStorybookとそのアドオンで利用されるUIコンポーネントライブラリです。
このライブラリからは`Form.Button`のように複数のボタンコンポーネントが散らばっていました。
バージョン8では1つの`Button`に纏まりました(`IconButton`だけは別として残っています)。
さらに、`Button`、`IconButton`のpropsがいくつか変更されました。
`isLink`が非推奨になって`asChild`を使うように、`small`が非推奨になって`size`を使うように、その他いくつかのpropsが非推奨になって`variant`でまとめて変更できるようになります。

`@storybook/components`からアイコンがいくつか提供されていましたが、今後はそれが非推奨となります。
別のライブラリの`@storybook/icons`から提供されるものを使うことが推奨されます。

## 今後のバージョンアップ予定
2024年1月29日にbeta版のリリース、2024年2月13日にRelease Candidate版としてリリース、2024年2月27日にstable版としてリリースされる予定です。

https://github.com/storybookjs/storybook/discussions/25276?ref=storybookblog.ghost.io