Closed54

Storybook v6.x を v7.x に移行して Next.js v14 で使えるようにするスレ

ピン留めされたアイテム
snakasnaka

背景

Next.js のバージョンを v12 から v13 に上げたタイミングで、それまで動いていた(いろいろ問題ありながら) Storybook v6.5 が動かなくなった。
なんとか Storybook なしで進めてきたが、いつの間にか Next.js も v13 から v14 に上がってしまった。
さすがに辛くなってきたので Storybook を使えるようにしたい。

バージョンとか

以前(動いていた)

  • Next.js v12.3.4
  • Storybook v6.5.16

目標地点

  • Next.js v14.0.4
  • Storybook v7.4.5 ( 今となってはちょっと古くなってしまったが、まずはこのバージョンで... )
snakasnaka

@storybook/addon-storysource のエラー

node_modules/@storybook/addon-storysource/preset.js:1
import './dist/preset';
^^^^^^

SyntaxError: Cannot use import statement outside a module

関係しそうな Issue は以下
https://github.com/storybookjs/storybook/issues/23972

snakasnaka

storysource それほど重要でもなくなんとなく使ってただけなので、深追いはせず外すことにした。

addon-storysource を外すことでエラーは解消した。

snakasnaka

TypeError: docsParameter.renderer is not a function というエラー

以下、関係していそうな箇所

https://github.com/storybookjs/storybook/blob/8b47f90496d7ad416cfcd8f1b25adfb9d197b830/code/lib/preview-api/src/modules/preview-web/render/CsfDocsRender.ts#L121-L128

snakasnaka

@storybook/addon-docsmain.ts に追加したらエラーは解消した

.storybook/main.ts
  addons: [
    ...
     '@storybook/addon-controls',
+    '@storybook/addon-docs',
     'storybook-react-i18next'
   ],
snakasnaka

package.json には @storybook/addon-docs が無かったが、 @storybook/addon-essentials に含まれていた。

( addon-essentials に含まれる addon )

    "@storybook/addon-actions" "7.4.5"
    "@storybook/addon-backgrounds" "7.4.5"
    "@storybook/addon-controls" "7.4.5"
    "@storybook/addon-docs" "7.4.5"
    "@storybook/addon-highlight" "7.4.5"
    "@storybook/addon-measure" "7.4.5"
    "@storybook/addon-outline" "7.4.5"
    "@storybook/addon-toolbars" "7.4.5"
    "@storybook/addon-viewport" "7.4.5"
snakasnaka

TypeError: _addons.default.getChannel is not a function のエラー

スタックトレースから MUI およびその Theme 関連が関係してそうだったので、以下の記事を確認

https://storybook.js.org/recipes/@mui/material

snakasnaka

main.ts に @storybook/addon-themes を追加し、 storybook-addon-material-ui5 を外した

package.json
@@ -49,6 +49,7 @@
     "@storybook/addon-backgrounds": "7.4.5",
     "@storybook/addon-controls": "7.4.5",
     "@storybook/addon-links": "7.4.5",
+    "@storybook/addon-themes": "7.4.5",
     "@storybook/addons": "7.4.5",
     "@storybook/nextjs": "7.4.5",
     "@storybook/react": "7.4.5",
@@ -57,7 +58,6 @@
     "@types/papaparse": "5.3.14",
     "@types/react": "18.2.45",
     "@types/react-dom": "18.2.17",
-    "storybook-addon-material-ui5": "1.0.0",
     "ts-prune": "0.10.3"
   }
main.ts
   addons: [
     ...
     '@storybook/addon-docs',
+    '@storybook/addon-themes',
     'storybook-react-i18next'
   ],
snakasnaka

preview.tsx で theme と global CSS を設定することでエラーは解消した

preview.tsx
@@ -1,9 +1,11 @@
 import React from 'react'
-import { muiTheme } from 'storybook-addon-material-ui5'
+import { CssBaseline, ThemeProvider } from '@mui/material'
+import { withThemeFromJSXProvider } from '@storybook/addon-themes'
 import { theme } from '../src/styles/theme'

@@ -19,19 +21,31 @@
const preview: Preview = {
+  decorators: [
+    withThemeFromJSXProvider({
+      themes: {
+        default: theme
+      },
+      defaultTheme: 'default',
+      Provider: ThemeProvider,
+      GlobalStyles: CssBaseline
+    })
+  ]
 }
snakasnaka

TypeError: Cannot redefine property: default というエラー

かつて next/image に対処するため、以下のようなコードを preview.js に記述していたのが原因

preview.js
import * as nextFutureImage from 'next/image'

Object.defineProperty(nextFutureImage, 'default', {
  configurable: true,
  value: props => <img {...props} />
})

@storybook/nextjs によって、このような hack は不要になったので削除した。

https://www.npmjs.com/package/@storybook/nextjs#nextjss-image-component

snakasnaka

Image with src "https://hogehoge... " is missing required "width" property というエラー

以前は width / height の省略を許していたみたいだけど、それが許されなくなったっぽいので story でそれらを利用する箇所に width, heightを追加する。 ( これは Storybook というより Next.js のコンポーネントの利用方法の問題 )

https://nextjs.org/docs/pages/building-your-application/optimizing/images#image-sizing

snakasnaka

以前は width / height の省略を許していたみたい

この認識は誤りで、 preview.js での以下の hack で next/imageImage コンポーネントがネイティブの img タグに置き換わっていたため、 width / height の省略が許されていただけだった。

preview.js
Object.defineProperty(nextFutureImage, 'default', {
  configurable: true,
  value: props => <img {...props} />
})
snakasnaka

MUI: Can not find the date and time pickers localization context というエラー

It looks like you forgot to wrap your component in LocalizationProvider.
This can also happen if you are bundling multiple versions of the `@mui/x-date-pickers` package

こちらも Storybook v7 の問題というより、利用しているコンポーネントの設定問題

snakasnaka

以下のように decorators に LocalizationProvider を追加することで解決した。

preview.tsx
-import { Preview } from '@storybook/react'
+import { DecoratorFunction } from '@storybook/types'
+import { Preview, ReactRenderer } from '@storybook/react'
+import { LocalizationProvider } from '@mui/x-date-pickers'
+import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'
 
 
+const withLocalizationProvider: DecoratorFunction<ReactRenderer> = Story => (
+  <LocalizationProvider dateAdapter={AdapterDateFns}>
+    <Story />
+  </LocalizationProvider>
+)

 const preview: Preview = {
   parameters: {
     backgrounds: {
@@ -39,7 +48,8 @@ const preview: Preview = {
       Provider: ThemeProvider,
       GlobalStyles: CssBaseline
     }),
-    withRecoil
+    withRecoil,
+    withLocalizationProvider
   ]
 }
snakasnaka

smoke test が ModuleDependencyWarning: Critical dependency: require function is used in a way in which dependencies cannot be statically extracted というエラーで失敗する

ブラウザの console とかにも出てたけど warning だったのでスルーしてた...

関係しそうな Issue

https://github.com/storybookjs/storybook/issues/21844

https://github.com/storybookjs/storybook/issues/21316

@storybook/nextjs のコードで発生しているように見える

snakasnaka

ちゃんとメッセージ読むか...

../../node_modules/@storybook/nextjs/dist/chunk-FFRTCGB4.mjs 1:224-231Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
../../node_modules/@storybook/nextjs/dist/chunk-FFRTCGB4.mjs 1:353-360Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
snakasnaka

Warning が出るものの、とりあえず動いてはいるので一旦無視してみる

https://webpack.js.org/configuration/other-options/#ignorewarnings

.storybook/main.ts
@@ -25,6 +25,13 @@ const config: StorybookConfig = {
       }
     })
     config.resolve!.extensions!.push('.ts', '.tsx')
+    config.ignoreWarnings = [
+      {
+        message:
+          /Critical dependency: require function is used in a way in which dependencies cannot be statically extracted/
+      }
+    ]
     return config
   },
 
snakasnaka

Duplicate stories with id: xxx-xxx-xxx というエラーが Storybook サーバ側に出ていた

12% building 0/2 entries 125/213 dependencies 3/69 modulesWARN 🚨 Unable to index files:
WARN - ./src/components/molecules/Hoge/index.stories.tsx,./src/components/molecules/Fuga/index.stories.tsx: Duplicate stories with id: molecules-xxxx--default
WARN - ./src/components/molecules/Hoge/index.stories.tsx,./src/components/molecules/Fuga/index.stories.tsx: Duplicate stories with id: molecules-xxxx--less-texts
snakasnaka

stories の export default オブジェクトで設定している title プロパティが HogeFuga で重複していたのが原因だった。

title にセットする値をユニークな名前にしたらエラーは解消した

src/components/molecules/Hoge/index.stories.tsx
export default {
  component: Hoge,
  title: 'molecules/xxxx'  // <-- ここが重複してた
}
snakasnaka

prettier.resolveConfig is not a function が出るようになってしまった

これまで出なかったのが出るようになってしまった ...

https://github.com/prettier/prettier/issues/15022

eslint-plugin-prettier の問題っぽい?

snakasnaka

利用しているバージョンは以下

    "eslint-plugin-prettier": "5.0.1",
    "prettier": "3.0.3",
snakasnaka

node_modules 消して yarn install し直したらエラーは解消した... (根本原因不明)

snakasnaka

TypeError: (0 , next_font_google__WEBPACK_IMPORTED_MODULE_0__.Noto_Sans_JP) is not a function というエラーがページに出る

next/font/google はサポートしているはずだが... ?

You don't have to do anything. next/font/google is supported out of the box.
https://www.npmjs.com/package/@storybook/nextjs#nextjs-font-optimization

snakasnaka

エラーは以下の箇所で発生している

runtime.js
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   exo: () => (/* binding */ exo),
/* harmony export */   notoSansJP: () => (/* binding */ notoSansJP),
/* harmony export */ });
/* harmony import */ var next_font_google__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! next/font/google */ "../../node_modules/next/font/google/index.js");
/* harmony import */ var next_font_google__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_font_google__WEBPACK_IMPORTED_MODULE_0__);

var notoSansJP = (0,next_font_google__WEBPACK_IMPORTED_MODULE_0__.Noto_Sans_JP)({
  weight: ['400', '500', '700'],
  preload: false
});
snakasnaka

切り分けのために、Noto Sans JP を Exo などに置き換えてみる.

snakasnaka

置き換えた font が読み込めていないので next/font がうまく動いてなさそう。

TypeError: (0 , next_font_google__WEBPACK_IMPORTED_MODULE_0__.Exo) is not a function
snakasnaka

いったん、next/font/google を使わない方向に切り替えてみて、あとで対処する。

snakasnaka

その後以下の調査で、 Babel と Webpack の動作が鍵になりそうだと判明し、 .storybook/main.ts に使っているのかよくわからない babel の設定があったので削ったら動くようになった

https://zenn.dev/snaka/scraps/8e4f6f8dacb56c#comment-d58b1e7f2273de

.storybook/main.ts
@@ -5,10 +5,7 @@ import { StorybookConfig } from '@storybook/nextjs'
 // Export a function. Accept the base config as the only param.
 const config: StorybookConfig = {
   stories: ['../src/components/**/*.stories.tsx'],
 
-  babel: { /* ... babel config ... */ },
-
   docs: {
     autodocs: true
   }
snakasnaka

Cannot read properties of undefined (reading 'white') というエラーがページに出る

どうも theme の設定ができてなさそう?

エラー出しているのは以下の箇所

vendors-xxx-bundle.js
const body = theme => (0,_babel_runtime_helpers_esm_extends__WEBPACK_IMPORTED_MODULE_2__["default"])({
  color: (theme.vars || theme).palette.text.primary
}, theme.typography.body1, {
  backgroundColor: (theme.vars || theme).palette.background.default,
  '@media print': {
    // Save printer ink.
    backgroundColor: (theme.vars || theme).palette.common.white
  }
});
snakasnaka

break point 仕込んでみた感じ theme.palette.common.white を参照しようとしてるが、common が無さそう。

snakasnaka

今使っているバージョン

"@mui/material": "5.15.1",
snakasnaka

同じバージョン使ってて動いているものもあるので、theme についてそれとの差分を調べる。

snakasnaka

以下のように createTheme() の結果を渡すように修正したらエラーは解消した

.storybook/preview.tsx
const themeDecorator: DecoratorFunction<ReactRenderer> = withThemeFromJSXProvider({
  themes: {
-    default: getTheme('light', 'ja')
+    default: createTheme(getTheme('light', 'ja'))
  },
  defaultTheme: 'default',
  Provider: ThemeProvider,
  GlobalStyles: CssBaseline
})
snakasnaka

@storybook/next の README を読み直す

next/font/google の問題 の解決のヒントが無いか、読み直してみる。

https://github.com/storybookjs/storybook/tree/next/code/frameworks/nextjs

snakasnaka

https://github.com/storybookjs/storybook/tree/v7.6.6/code/frameworks/nextjs#mocking-fonts-during-testing

Occasionally fetching fonts from Google may fail as part of your Storybook build step. It is highly recommended to mock these requests, as those failures can cause your pipeline to fail as well. Next.js supports mocking fonts via a JavaScript module located where the env var NEXT_FONT_GOOGLE_MOCKED_RESPONSES references

Storybook のバージョン上げれば(今は 7.4.5) Google Fonts からの font ファイルダウンロードを mock する機能がある。

試してみる価値はありそう。

snakasnaka

ここまでで、ほとんどのコンポーネントが Storybook で動くようになったので一旦クローズする
後は気が向いたときに対応する。

このスクラップは2023/12/30にクローズされました