storybook: [Bug]: Nuxt 3 version 3.1.2: nuxt instance unavailable - useNuxtApp().$app.filters

Describe the bug

When using use methods from useNuxtApp().$app.filters storybook and vitest gives errors when using

To Reproduce

When using use methods from useNuxtApp().$app.filters storybook and vitest gives errors when using

a-avatar.stories.js

import AAvatar from './a-avatar.vue'

export default {
  title: 'Атомы/a-avatar',
  component: AAvatar,
  parameters: {
    docs: {
      description: {
        component:
          // eslint-disable-next-line max-len
          'Компонент вывода аватара — это настраиваемый компонент, который обычно используется для отображения профиля пользователя в виде изображения, значка или короткого текста',
      },
    },
  },
  argTypes: {
    type: {
      description: 'Тип аватара',
      options: ['film', 'user'],
      control: {
        type: 'radio',
      },
    },
    withInitials: {
      description: 'Включение отображения инициалов',
      table: {
        defaultValue: {
          summary: true,
        },
      },
      control: {
        type: 'boolean',
      },
    },
    name: {
      description: 'Имя',
      control: {
        type: 'text',
      },
    },
    surname: {
      description: 'Фамилия',
      control: {
        type: 'text',
      },
    },
    photoSrc: {
      description: 'Путь до изображения',
      control: {
        type: 'text',
      },
    },
    profession: {
      description: 'Профессия',
      control: {
        type: 'text',
      },
    },
    counter: {
      description: 'Счетчик',
      table: {
        defaultValue: {
          summary: 0,
        },
      },
      control: {
        type: 'number',
      },
    },
  },
}

const Template = (args) => ({
  components: { AAvatar },
  setup() {
    return { args }
  },
  template: '<AAvatar v-bind="args" />',
})

export const Film = Template.bind({})
Film.args = {
  type: 'film',
  name: 'Иван',
  surname: 'Иванов',
  profession: 'тестеровщик',
}

export const FilmWithPhoto = Template.bind({})

a-avatar.vue

<template>
  <div class="a-avatar__wrapper">
    <div v-if="counter && !filmAvatar" class="a-avatar__counter">
      {{ counterText }}
    </div>
    <div
      class="a-avatar"
      :class="[avatarTypeClass, photoSrc && 'a-avatar--photo']"
      :style="{ backgroundImage: photoSrc ? `url('${photoSrc}')` : 'none' }"
    >
      <span v-if="!photoSrc && withInitials" class="a-avatar__initials">
        {{ initials }}
      </span>
      <i v-else-if="avatarWithIcon" class="a-icons icon-user a-avatar__icon" />
    </div>
    <div v-if="filmAvatar" class="a-avatar__info">
      <h6 class="a-avatar__info-name font-body">
        <span>{{ name }}</span>
        <span>{{ surname }}</span>
      </h6>
      <h6 class="a-avatar__info-profession font-body">
        {{ profession.toLowerCase() }}
      </h6>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { useNuxtApp } from 'nuxt/app'
import { computed } from 'vue'

const props = defineProps({
  /**
   * Тип аватара: film или user.
   */
  type: {
    type: String,
    default() {
      return avatarVariants.types[0]
    },
    validator(value: string) {
      return useNuxtApp().$app.filters.validatePropStringByArray(value, avatarVariants.types)
    },
  },
  /**
   * Включение отображения инициалов
   */
  withInitials: {
    type: Boolean,
    default: true,
  },
  /**
   * Имя
   */
  name: {
    type: String,
    default: '',
  },
  /**
   * Фамилия
   */
  surname: {
    type: String,
    default: '',
  },
  /**
   * Путь до изображения
   */
  photoSrc: {
    type: [String, Boolean],
    default: false,
  },
  /**
   * Профессия
   */
  profession: {
    type: String,
    default: '',
  },
  /**
   * Счетчик
   */
  counter: {
    type: Number,
    default: 0,
  },
})

const avatarTypeClass = computed(() => {
  return useNuxtApp().$app.filters.setAtomClassByProp(props.type, avatarVariants.types, 'a-avatar')
})

const filmAvatar = computed(() => {
  return props.type === 'film'
})

const avatarWithIcon = computed(() => {
  return props.type === 'user' && !props.photoSrc
})

const counterText = computed(() => {
  return props.counter > 99 ? '+' : props.counter
})

const initials = computed(() => {
  return `${props.name[0]?.toUpperCase()}${props.surname[0]?.toUpperCase()}`
})
</script>

<script lang="ts">
const avatarVariants = {
  types: ['film', 'user'],
}
</script>

<style lang="scss" src="./a-avatar.scss" />

System

Environment Info:

  System:
    OS: macOS 13.1
    CPU: (10) arm64 Apple M1 Pro
  Binaries:
    Node: 16.17.0 - ~/.nvm/versions/node/v16.17.0/bin/node
    Yarn: 3.2.4 - ~/node_modules/.bin/yarn
    npm: 8.15.0 - ~/.nvm/versions/node/v16.17.0/bin/npm
  Browsers:
    Chrome: 110.0.5481.100
    Firefox: 107.0
    Safari: 16.2
  npmPackages:
    @storybook/addon-a11y: ^6.5.16 => 6.5.16 
    @storybook/addon-essentials: ^6.5.16 => 6.5.16 
    @storybook/builder-vite: ^0.3.0 => 0.3.0 
    @storybook/vue3: ^6.5.16 => 6.5.16

Additional context

nuxt instance unavailable


Error: nuxt instance unavailable
    at useNuxtApp (http://localhost:6006/node_modules/.vite-storybook/deps/nuxt_app.js?v=9a516d33:424:13)
    at validator (http://localhost:6006/components/_ui/atoms/a-avatar/a-avatar.vue?t=1674476744983:16:16)
    at validateProp (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:4842:21)
    at validateProps (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:4816:5)
    at initProps (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:4567:5)
    at setupComponent (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:7114:3)
    at mountComponent (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:5901:7)
    at processComponent (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:5879:9)
    at patch (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:5597:11)
    at ReactiveEffect.componentUpdateFn [as fn] (http://localhost:6006/node_modules/.vite-storybook/deps/chunk-HK4EIWFA.js?v=9a516d33:5992:11)

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 2
  • Comments: 47 (18 by maintainers)

Most upvoted comments

@chakAs3 Hey! This problem is still relevant. We can’t use composable useNuxtApp() in storybook stories. This severely limits the ability to use storybook with Nuxt 3. Are there any options to make it work?

@chakAs3 And when will we be able to come up with an alternative? We have a DI container in useNuxtApp, in which the entire core architecture of the project is located. And it is impossible to emulate it in every story

@chakAs3 Good afternoon

Are there any changes in this matter? Is there anything to test/change in the settings?

@nearking try

npx storybook-nuxt init and change in packages.json version "@storybook-vue/nuxt": "[^0.2.0]", and again run install

Salam @Ibochkarev, please can you use the latest version of @storybook-vue/nuxt recently published, it may fix your issue inshallah update nuxt to latest i think 3.8.1

Hi @VegasChickiChicki I put nuxt integration as a priority this week so I will notify you once it is ready for test

Hi @FieldMarshallVague i really appreciate your work, it definetly helps, i will get sometime this week to work on it. i know the nuxtapp issue i have already some ideas to make it work properly. i let you know if i need your help on something . Thanks again

I have the same issue, I have some components working with my nuxt project, but now I am adding one with ‘useNuxtApp’ in it (pulling in a plugin) and it fails.

My component has this:

const { $debounce } = useNuxtApp()

And my preview.ts is like this:

import { setup } from '@storybook/vue3'
import { createPinia } from 'pinia'
// import { useNuxtApp } from '#app'
// import { useNuxtApp } from 'nuxt/dist/app'

/**
 * This is used by the preview panel in the storybook UI.
 * Setup global deps for previewing components here, to avoid duplication.
 */

/** @type { import('@storybook/vue3').Preview } */
const preview: import('@storybook/vue3').Preview = {
  parameters: {
    backgrounds: {
      default: 'light',
    },
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
}

export default preview

const pinia = createPinia()

// const { $debounce } = useNuxtApp()

setup((app) => {
  app.use(pinia)
  // app.use($debounce)
})

// NOTE: I have commented out my attempt to import useNuxtApp function

And I get ‘useNuxtApp is undefined.’

As you can see, I’ve tried providing it to the preview setup. If I uncomment the lines above that import the useNuxtApp function into preview.ts then I get this error:

12:02:40 [vite] Internal server error: Missing "./dist/app" specifier in "nuxt" package
  Plugin: vite:import-analysis
  File: C:/sb-test/.storybook/preview.ts
      at e (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:14845:25)
      at n (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:14845:627)
      at o (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:14845:1276)
      at resolveExports (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:22033:20)
      at resolveDeepImport (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:22052:31)
      at tryNodeResolve (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:21737:20)
      at Context.resolveId (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:21488:28)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async Object.resolveId (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:41612:32)
      at async TransformContext.resolve (file:///C:/sb-test/node_modules/vite/dist/node/chunks/dep-ca21228b.js:41363:23)

Any help here @storybookjs/vue ?

I will be working on it… but this may be a vite issue, I’m not sure but I will reproduce it and see!