Nuxt.js+StorybookでJSX記法がトランスパイルできないときはbabel.config.jsを用意する


Nuxtでjsx記法を使ったコンポーネントが、Storybookでトランスパイルに失敗するという問題に遭遇しました。

再現手順

まずnuxtのプロジェクトを作成して、Storybookを導入します。

npx crete-nuxt-app storybooksample
cd storybooksample
npx sb init

続いて、Jsxを使ったコンポーネントを作成し、storiesを用意します。

stories/HelloJsx.vue
<script>
export default {
  render(h) {
    return <div>Hello</div>
  },
}
</script>
stories/HelloJsx.stories.js
import Hello from './HelloJsx.vue'

export default {
  title: 'Example/Hello',
  component: Hello,
  argTypes: {},
}

const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Hello },
  template: '<hello />',
})

export const MyHello = Template.bind({})

この状態でyarn storybookを実行すると下のようなエラーが出ます。

ERROR in ./stories/HelloJsx.vue?vue&type=script&lang=js& (./node_modules/vue-docgen-loader/lib??ref--12!./node_modules/babel-loader/lib??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./stories/HelloJsx.vue?vue&type=script&lang=js&) 3:11
Module parse failed: Unexpected token (3:11)
File was processed with these loaders:
 * ./node_modules/vue-docgen-loader/lib/index.js
 * ./node_modules/vue-docgen-loader/lib/index.js
 * ./node_modules/babel-loader/lib/index.js
 * ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| export default {
|   render: function render(h) {
>     return <div>Hello</div>;
|   }
| };
 @ ./stories/HelloJsx.vue?vue&type=script&lang=js& 1:0-228 1:244-247 1:249-474 1:249-474
 @ ./stories/HelloJsx.vue
 @ ./stories/HelloJsx.stories.js
 @ ./stories sync ^\.(?:(?:^|[\\\/]|(?:(?:(?!(?:^|[\\\/])\.).)*?)[\\\/])(?!\.)(?=.)[^\\\/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./.storybook/generated-stories-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/vue/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addParameter.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined

解決

下記のファイルをプロジェクト直下に作成します。これは@vue/cliでvue create storybooktestとしてプロジェクトを作成したときに作られるものと同じ内容です。

babel.config.js
module.exports = {
  presets: ['@vue/cli-plugin-babel/preset'],
}

このモジュールをプロジェクトに追加しましょう。

yarn add -D @vue/cli-plugin-babel

これでOKです。Storybookを見てみましょう。

yarn storybook

うまく行きました。