storybook: Vuetify 2.0.2 not supported

Description: https://stackoverflow.com/a/56367842 The new style of latest version of vuetify 2.0.2 requires that vuetify be passed into new Vue()

My .storybook/config.js file:

import Vue from 'vue'
import { configure, addDecorator } from '@storybook/vue';
import StoryRouter from 'storybook-vue-router'
import VueRouter from 'vue-router'

// add vuetify
import '../src/plugins/vuetify'

// add router
Vue.use(VueRouter)
addDecorator(StoryRouter())

// add vuetify
addDecorator(() => ({
      template: '<v-app><v-content><story/></v-content></v-app>',
}))

// add stories
function loadStories() {
  const req = require.context('../src/components/stories', true, /.stories.ts$/);
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

My /plugins/vuetify.ts file:

import Vue from 'vue'
import Vuetify from 'vuetify'

Vue.use(Vuetify)

export default new Vuetify({
	theme: {
		dark: true,
		icons: {
			iconfont: 'fa',
		},
		options: {
			customProperties: true,
		},
		themes: {
			dark: {
				blue: '#002579',
				'dark-grey': '#464646',
				green: '#00BE96',
				grey: '#EEE8E8',
				orange: '#FE5F5A',
				primary: '#FE5F5A',
				white: '#FFFFFF',
			},
		},
	},
})```



The problem:
Receiving a seemingly unrelated error:

Cannot read property ‘dark’ of undefined TypeError: Cannot read property ‘dark’ of undefined at VueComponent.isDark (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:73337:34) at Watcher.get (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65400:25) at Watcher.evaluate (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65505:21) at VueComponent.computedGetter [as isDark] (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65755:17) at VueComponent.themeClasses (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:105182:29) at Watcher.get (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65400:25) at Watcher.evaluate (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65505:21) at Proxy.computedGetter (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:65755:17) at Proxy.render (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:73354:15) at VueComponent.Vue._render (http://localhost:9001/vendors~main.2f0c8252b2ad5480ce8f.bundle.js:64491:22)```

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 30 (12 by maintainers)

Most upvoted comments

I had the same issue. All you have to do is add vuetify to the addDecorator call.

// add vuetify
import vuetifyConfig from '../src/plugins/vuetify'

addDecorator(() => ({
      vuetify: vuetifyConfig,
      template: '<v-app><v-content><story/></v-content></v-app>',
}))

I was actually able to make it work with A-la-carte setup. See revised config.js at the bottom.

@kyleoliveiro @atgjack This setup doesn’t work for me. Vue won’t recognize custom Vuetify components. [Vue warn]: Unknown custom element: <v-app>... [Vue warn]: Unknown custom element: <v-card>... And so on for every Vuetify component. It renders:

<v-app>
  <v-card height="400" width="256" class="mx-auto"></v-card>
</v-app>

I configured Vuetify using Webpack install instructions and followed your advice configuring storybook with it’s own plugin config.

My .storybook/webpack.config.js

const path = require('path');

module.exports = async ({ config, mode }) => {

    config.module.rules = [
        ...config.module.rules,
        {
        test: /\.s(c|a)ss$/,
        use: [
            'vue-style-loader',
            'css-loader',
            {
                loader: 'sass-loader',
                options: {
                        implementation: require('sass'),
                        sassOptions: {
                            fiber: require('fibers'),
                            indentedSyntax: true
                        }
                    }
                }
            ]
        }
    ];

    config.resolve.alias = {
        ...config.resolve.alias,
        '@': path.resolve(__dirname, '../src')
    }

    return config;
};

.storybook/config.js below

import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import { configure, addDecorator } from '@storybook/vue'

Vue.use(Vuetify)

addDecorator(() => ({
    vuetify: new Vuetify(),
    template: '<v-app><story/></v-app>'
}))

configure(require.context('../stories', true, /\.stories\.js$/), module);

I don’t know why v-components wont register globally but I got it to work by following A-la-carte setup to register them explicitly. I import all from Vuetify, extract components only and register them all.

import Vue from 'vue'
import * as _Vuetify from 'vuetify/lib'
import { configure, addDecorator } from '@storybook/vue'

const Vuetify = _Vuetify.default

const isVueComponent = obj => obj.name === 'VueComponent'

const VComponents = Object.keys(_Vuetify).reduce((acc, key) => {
    if (isVueComponent(_Vuetify[key])) {
        acc[key] = _Vuetify[key]
    }
    return acc
}, {})

Vue.use(Vuetify, {
    components: {
        ...VComponents
    }
})

addDecorator(() => ({
    vuetify: new Vuetify(),
    template: '<v-app><story/></v-app>'
}))

configure(require.context('../stories', true, /\.stories\.js$/), module);

@morficus I was encountering the same issue as you. I solved it by creating a separate vuetify config file just for Storybook and using the full installation method for Vuetify inside of Storybook, so it doesn’t rely on VuetifyLoaderPlugin.

This way I could get Vuetify working in Storybook while still using VuetifyLoaderPlugin in my main application. Hope that helps.

Thanks for that mate!

So I could globally load all vuetify components with:

// .storybook/vuetify_storybook.js
import Vue from 'vue';
import Vuetify from 'vuetify'; // loads all components
import 'vuetify/dist/vuetify.min.css'; // all the css for components
import config from '../src/plugins/vuetifyConfig'; // basic config with theme

Vue.use(Vuetify);

export default new Vuetify(config);

And in case someone is interested the whole configuration:

// .storybook/main.js
const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links', '@storybook/addon-knobs'],

  webpackFinal: async (config, { configType }) => {

    // Use Sass loader for vuetify components
    config.module.rules.push({
      test: /\.s(a|c)ss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'],
      include: path.resolve(__dirname, '../'),
    });

    config.module.rules.push({
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '../src'),
          vue: 'vue/dist/vue.js',
          'vue$': 'vue/dist/vue.esm.js',          
        },
      },
    });

    // Return the altered config
    return config;
  },
};
// .storybook/preview.js
import { addDecorator } from '@storybook/vue';
import vuetify from './vuetify_storybook';

addDecorator(() => ({
  vuetify,
  template: `
    <v-app>
      <v-main>
        <v-container fluid >
          <story/>
        </v-container>
      </v-main>
    </v-app>
    `,
}));

btw. version:

storybook: 5.3.19
vuetify: 2.3.3

@morficus I was encountering the same issue as you. I solved it by creating a separate vuetify config file just for Storybook and using the full installation method for Vuetify inside of Storybook, so it doesn’t rely on VuetifyLoaderPlugin.

This way I could get Vuetify working in Storybook while still using VuetifyLoaderPlugin in my main application. Hope that helps.

Imho this issue should be reopened. I`ve got the same problem as @thomasvogelaar and @stingpan. Only after disabling the docs everything works as expected. Any ideas anyone?

Thank you @DomDomHaas, your set up also worked for me. I still did run into an issue when creating stories using Vuetify VSelect component. Those of you using @storybook/addon-essentials might encounter the same thing.

Specifically this is what I saw in the Chrome browser console:

TypeError: Cannot read property 't' of undefined
    at VueComponent.listData (vuetify.js:22647)
    at Watcher.get (vue.esm.js:4488)
    at Watcher.evaluate (vue.esm.js:4593)
    at VueComponent.computedGetter [as listData] (vue.esm.js:4845)
    at VueComponent.staticList (vuetify.js:22663)
    at Watcher.get (vue.esm.js:4488)
    at Watcher.evaluate (vue.esm.js:4593)
    at VueComponent.computedGetter [as staticList] (vue.esm.js:4845)
    at VueComponent.genList (vuetify.js:22896)
    at VueComponent.genMenu (vuetify.js:22944)

...

index.js:60 TypeError: Failed to execute 'observe' on 'IntersectionObserver': parameter 1 is not of type 'Element'.
    at Object.inserted (vuetify.js:32620)
    at VueComponent.mounted (vuetify.js:37737)
    at invokeWithErrorHandling (vue.esm.js:1863)
    at callHook (vue.esm.js:4228)
    at Object.insert (vue.esm.js:3148)
    at invokeInsertHook (vue.esm.js:6357)
    at Vue.patch [as __patch__] (vue.esm.js:6576)
    at Vue._update (vue.esm.js:3954)
    at Vue.updateComponent (vue.esm.js:4075)
    at Watcher.get (vue.esm.js:4488)

From process of elimination, I narrowed it down to something to do with Storybook’s Docs add-on that comes from including @storybook/addon-essentials in main.js. I wasn’t using the Docs add-on anyway so I’ve disabled it to fix this issue:

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    {
      name: "@storybook/addon-essentials",
      options: {
        docs: false
      }
    }
  ]
...

ok I got this working with the following config. Hoping this helps someone in the future. The difference between the sass and the scss rules are the semicolon at the end of the imported styles.scss file. One expects semicolons and one doesn’t so combining them into 1 loader became impossible.

Frankly getting Storybook working with Vuetify is entirely too much trouble

const path = require('path');

module.exports = async ({ config }) => {

  function resolve(dir) {
    return path.join(__dirname, '..', dir);
  }

  /** removes existing scss rule */
  config.module.rules = config.module.rules.filter(rule =>
    !rule.test.test('.scss')
  )
  config.module.rules.push({
    test: /\.sass$/,
    use: [
      'vue-style-loader',
      'css-loader', {
        loader: 'sass-loader',
        options: {
          implementation: require('sass'),
          data: `
            @import '@/styles/styles.scss'
          `,
        }
      },
    ],
  }, {
    test: /\.scss$/,
    use: [
      'vue-style-loader',
      'css-loader', {
        loader: 'sass-loader',
        options: {
          implementation: require('sass'),
          data: `
            @import '@/styles/styles.scss';
          `,
        }
      },
    ],
  })

  config.resolve = {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
  };

  return config;
}; 

@morficus I was encountering the same issue as you. I solved it by creating a separate vuetify config file just for Storybook and using the full installation method for Vuetify inside of Storybook, so it doesn’t rely on VuetifyLoaderPlugin. This way I could get Vuetify working in Storybook while still using VuetifyLoaderPlugin in my main application. Hope that helps.

Thanks for that mate!

So I could globally load all vuetify components with:

// .storybook/vuetify_storybook.js
import Vue from 'vue';
import Vuetify from 'vuetify'; // loads all components
import 'vuetify/dist/vuetify.min.css'; // all the css for components
import config from '../src/plugins/vuetifyConfig'; // basic config with theme

Vue.use(Vuetify);

export default new Vuetify(config);

And in case someone is interested the whole configuration:

// .storybook/main.js
const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links', '@storybook/addon-knobs'],

  webpackFinal: async (config, { configType }) => {

    // Use Sass loader for vuetify components
    config.module.rules.push({
      test: /\.s(a|c)ss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'],
      include: path.resolve(__dirname, '../'),
    });

    config.module.rules.push({
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '../src'),
          vue: 'vue/dist/vue.js',
          'vue$': 'vue/dist/vue.esm.js',          
        },
      },
    });

    // Return the altered config
    return config;
  },
};
// .storybook/preview.js
import { addDecorator } from '@storybook/vue';
import vuetify from './vuetify_storybook';

addDecorator(() => ({
  vuetify,
  template: `
    <v-app>
      <v-main>
        <v-container fluid >
          <story/>
        </v-container>
      </v-main>
    </v-app>
    `,
}));

btw. version:

storybook: 5.3.19
vuetify: 2.3.3

This solution worked for me. except that I had to import config in vuetify_storybook.js file from different path as

import config from '../../vue.config';

Thanks a lot @DomDomHaas !

Here is how I got vuetify-loader to at least partially auto-import vuetify components.

storybook@5.3.3 vuetify-loader@1.4.3 vuetify@2.2.4 vue-cli-plugin-storybook@1.1.0

// vue.config.js
module.exports = {
  transpileDependencies: ["vuetify"],
  pluginOptions: {
    storybook: {
      allowedPlugins: ["VuetifyLoaderPlugin"]
    }
  }
};

Now if I use <v-btn> for example within a component that I import into a story, VBtn is automatically imported and registered by vuetify-loader. No warnings in the console and button looks fine visually.

However, if I use any vuetify component within a story definition itself, I get warnings about components that haven’t registered. So if you are to use specific vuetify components within the story file, you have to manually register them:

// config/storybook/preview.js
import Vue from "vue";
import { addDecorator, configure } from "@storybook/vue";
import config from "../../src/plugins/vuetify";
import Vuetify, { VApp } from "vuetify/lib";

Vue.use(Vuetify, {
  components: {
    // Vuetify components used in stories need to be manually registered.
    // vuetify-loader cannot pick them up automatically. Presumably because how
    // storybook requires stories?!
    VApp,
  }
});

addDecorator(() => ({
  // 'config' includes the theme configuration (object) only
  vuetify: new Vuetify(config),
  render() {
    return (
      <v-app>
        <story />
      </v-app>
    );
  }
}));

configure(require.context("../../src", true, /\.stories\.js$/), module);

Maybe someone understands why this behaviour and how to make it easier?

@LeBenLeBen

Isn’t the decorator needed in any case? The components must be wrapped within a VApp element for the styling to be applied properly.

Ah, my bad. We can’t eliminate the need for the decorator anyway. Also, the correct problem is “we can’t access Vue root instance” not “we can’t Vue.use” (updated original comment).

Also passing the Vuetify instance to the root Vue component is also needed according to Vuetify docs, Vue.use() is not enough, see Webpack install.

Do you mean this? It seems it’s working without it according to comments… I thought the vuetify injection on the decorator is for this 🤔

new Vue({
  vuetify,
}).$mount('#app')

I (and some contributors) acknowledge the root instance problem but there seems no actions taken yet.

Relavant one: https://github.com/storybookjs/storybook/issues/13862

What I said is the “vuetify does not work when Docs Addon enabled”. This is clearly Docs Addon, especially its rendering/source generation mechanisms’ problem, since the same user code working on Canvas (normal preview). Docs Addon too have the root instance problem but we shouldn’t mix these so to make these easier to work on.

@morficus I was encountering the same issue as you. I solved it by creating a separate vuetify config file just for Storybook and using the full installation method for Vuetify inside of Storybook, so it doesn’t rely on VuetifyLoaderPlugin.

This way I could get Vuetify working in Storybook while still using VuetifyLoaderPlugin in my main application. Hope that helps.

This approach no longer works for Vuetify 2 since there is no more “Full installation method”.

I’m having the same issue as @antoniancu; Unable to customize the Vuetify theme for Storybook.

The approach suggested by @atgjack does not work, as Storybook complains that the Vuetify components are not registered.

Please re-open this issue @backbone87