📖

Storybook 8.x + MSW 2.x にアップグレードしてみた

2024/08/07に公開

はじめに

2024年3月13日にStorybook v8.0.0がリリースされました。
下記の通り、多くの機能の追加や改善がなされています。

https://storybook.js.org/blog/storybook-8

導入にはライブラリ本体だけでなく各種addonのアップグレードやそれに伴うコードの修正が必要ですが、それらを自動で一括アップグレードしてくれるツールが提供されており、

npx storybook@latest upgrade

で実行可能です。
しかし、Storybookの公式でないaddon等を使用している場合、自動アップグレードのみでは対応できず、手動でのアップグレードや書き換えが必要となります。

例えば、私の所属するプロジェクトではAPIのモックにMock Service Worker(MSW)を利用していますが、Storybook 8の導入と同時に、Storybookのaddonであるmsw-storybook-addon、更にはMSW本体の1.x→2.xへのアップグレードが必要です。

https://mswjs.io/

https://github.com/mswjs/msw-storybook-addon

後述の通り、MSW 2.xではモックの記述方法等に破壊的な変更がなされており、Storybookに関係する多くの箇所で書き換えが必要となり、ライブラリのアップデートと併せてかなり手間のかかる作業となりました。

私自身かなり手探りでの作業となったため、備忘録的に作業内容を本記事に記します。

なお、本記事では主だったものを記載しているため、一部作業内容を省略しています。詳細は公式のマイグレーションガイドをご参照ください。

https://storybook.js.org/docs/migration-guide

作業内容

MSW関係のライブラリのアップグレード

Storybook 8への自動アップグレードでエラーが発生してしまうため、MSW関係のライブラリを事前にアップグレードしておく必要があります。

私のプロジェクトではBFFフレームワークにtRPCを採用しており、前述のMSWやmsw-storybook-addonの他に、MSWによるモックをtRPCのrouterに登録することができるmsw-trpcを利用しており、これらのライブラリを事前にアップグレードしました。

https://trpc.io/

https://github.com/maloguertin/msw-trpc

なお、msw-trpcの安定版はv1.3.4となっていますが、2024年8月7日現在、READMEにある通りMSW 2.x対応にはpre-release版を利用する必要があるため、v2.0.0-beta.1へアップグレードしました。

Storybook 8への自動アップグレード

npx storybook@latest upgradeで自動アップグレードを実行しました。

なお、私のプロジェクトではBabelを利用しているため、アップグレードに伴い別途対応が必要となりました。ドキュメントの通り

npx storybook@latest add @storybook/addon-webpack5-compiler-babel

とすると、依存関係の更新や関係するファイルの書き換えなどを自動で行ってくれます。

https://storybook.js.org/docs/builders/webpack#compiler-support

モック関数の書き換え

MSW1.x→2.xでは破壊的な変更がなされていますが、この中で特に大きいのがモック関数の書き方が変更になったことでした。

https://mswjs.io/docs/migrations/1.x-to-2.x#breaking-changes

バージョンアップにより、モック関数がかなりシンプルに書けるようになりました。例えば、顧客情報を取得するAPIをモックする関数を例に取ると、

  • 変更前
mswTrpc.customer.findOne.query((req, res, ctx) => {
  return res(ctx.status(200), ctx.data({ id: '1', name: 'hoge' }));
}),
  • 変更後
mswTrpc.customer.findOne.query(() => {
  return { id: '1', name: 'hoge' };
}),

となります。

これから新規実装する場合はかなり見通しが良くなったと思うのですが、既存のコードは全て新しい書き方に書き換える必要がありました。私のプロジェクトではモック関数はすでに100箇所以上定義されており、おそらくこれらの書き換えは本記事の中で一番手数のかかった部分です。

jest.polyfills.jsの設定

MSW1.x→2.xのマイグレーションガイドのFrequent Issuesにある、Jestまわりのエラーが私のプロジェクトにも発生しました。

https://mswjs.io/docs/migrations/1.x-to-2.x#requestresponsetextencoder-is-not-defined-jest

別途polyfillを設定する必要があるため、マイグレーションガイド通りにjest.polyfills.jsを設定しましたが、別のエラーが発生してしまいました。

これについてはMSWのDiscussionsで議論されており、下記の通りに設定することでエラーを解消しました。

https://github.com/mswjs/msw/discussions/1934#discussioncomment-9494612

@storybook/test導入に伴う対応

Storybook中のReactコンポーネントのテストを書くのに@storybook/testing-libraryを利用していましたが、このプラグインがdeprecatedになり、新たに @storybook/test に置き換わりました。(Storybook 8のアップグレードツールにより自動で更新されます。)

https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-storybooktesting-library-package

この際、おそらく依存する@testing-library/user-eventのバージョンが変わったためか、userEventのメソッドの型が変わったようです。具体的には、Promiseを返していなかったのがバージョンアップによりPromiseを返すようになりました。

以前は想定通りテストが通ればよしということで、きちんと非同期処理が書かれているかはあまり気にしていませんでした。しかし、私のプロジェクトにはESLintのルールに@typescript-eslint/no-floating-promisesが設定されているため、userEventメソッドが呼ばれている箇所全てにPromiseチェーンまたはasync/awaitを書く必要が生じました。

この作業でも100箇所以上を書き換えることになったため、大きく手数がかかりました。

おわりに

以上がStorybook 8.x + MSW 2.x導入に伴って生じた主な作業内容です。

かなり手探りでの作業となりましたが、こういうときこそ基本に立ち返って、

  • READMEの内容を理解したか
  • エラーメッセージの内容をちゃんと読んでいるか
  • IssuesやDiscussionsで同じような内容が議論されていないか

ことが重要だと改めて感じました。

最後までお読みいただき、ありがとうございました。

スタフェステックブログ

Discussion