You probably know this story.
You go to start a brand new Vue + Vuetify project. You think,
Hmmm… I think I’d like to use Storybook to build and test my components in relative isolation.
–me, every time I start a new project
(BTW, if you don’t know what Storybook is, the 2-ish minute video below gives a pretty decent overview.) So you go to install it and you find that one or more of the following things has happened since the last time you did this:
- There’s a new version of Storybook
- There’s a new version of Vuetify
- There’s a new version of (node|ecmascript|vue|shiny-new-best-practice)
And of course, even if you have a perfectly valid working version of Storybook already configured in your last project–it doesn’t work anymore. 🙁
And of course, enough time has passed that you don’t really remember the details of why you configured it the way you did the last time, so you have to spend most of a day re-learning it to figure out how to make it work again. How many actual components could you actually have built in that same span of time? Who knows, but we <3 progress.
So, in the vain hope that it won’t change too much between this time and the next time, here’s my latest stab at configuring Storybook to work with Vue and Vuetify. The following assumes you’ve already got a working Vue+Vuetify app created.
Install Storybook + Addons
So far so good. This new installer automatically figures out I’m using Vue and sets me up for that. The a11y (accessibility) plugin is for reminding me to implement, well, accessibility features into my components. The other two are just so I can get the cool dark theme in the Storybook UI.
Go to the dark side
To get the Storybook UI to display in dark mode add this file to the config directory:
This is totally unnecessary, but I’ve found I like dark themes in the apps I use a lot…
Get SASSy
These updates get made to the .storybook/main.js
file:
The trickiest part is getting the SASS rule typed in correctly. Note that if I decide to switch to SCSS or to save the variables.sass
file in a different directory (must be either sass|scss|styles
), I need to update this rule to match. Also, if using SCSS, then I might not need the indentedSyntax
rule. I dunno. I almost always have to look this up, and it always seems to take forever to find the docs.
Wrap It Up
This was new. Last time I followed John Leider’s approach and created a custom add-on with a decorator to wrap all my component stories in Vuetify clothing. However, this repo has been archived. Shit, now that I’m writing this, I realize there’s a new version of that plugin. No matter, it appears the plugin is designed for the old version of Storybook (5.x).
The newer version of Storybook (6.x) lets you put a “decorator” right in the .storybook/preview.js
file. You could probably do that before. There’s probably a more elegant way to do this, but I’m slowly, slowly learning that working code is better than perfect code. Here’s my wrapper:
The props
and watch
sections of my wrapper are there so you can toggle between languages (i18n) and the dark|light themes when viewing your components in Storybook. If you have other app-level settings you’d like to be able to mess with while building/testing your components, you should put them here.
Export Options
In order for the above decorator to work, you have to set up your core Vuetify options so that they are exported as an object. Here’s how I do it:
Doing it this way allows you to re-use the options in your Storybook config. That way, if you change your app’s options, they will automatically be reflected in Storybook.
Help is on the way
I borrowed this style of creating stories from John’s plugin. I modified it this time to simplify and flatten the structure needed to generate docs from stories. This file could really go almost anywhere, but this seems like a decent location.
A First Story
With the above helper in place, your stories can look something like:
What the Font!?!
The fonts I specified in src/sass/variables.sass
aren’t showing up! Here’s my SASS:
Oh! Right, I need to create a preview-head.html
so they’ll be imported:
This is basically the same as the old version of Storybook.
That’s about it!
God I hope this configuration info is still relevant by the time I start y next project!! Even though Vue 3 has just been launched, I suspect that won’t be too much of a problem. Of course, Storybook 7 is probably less than a year away. Not to mention that the Vuetify team is bearing down on Vuetify 3. I expect that in a couple of months.
Sigh.
Such is the life of a developer these days. Hope this will be useful to someone. Get it while it’s hot!
Do you have a git repo with the done code?
Unfortunately, all of the projects I’ve used this more recent process in are in private repos. :/
Hi Morgan,
Thank you! This was pretty handy today. I wondered the same infamous quote (“um…hey…storybook!”) and lost a few hours of my life. But you have some helpful guidance in here.
One possible error in the article is this line for webpack:
prependData:
@import '@/sass/variables.sass'
,When I tried to use this, it was chocking on the
elements. I’m guessing maybe your blog posting engine did that? I removed them and just wrapped it in quotes like this:
prependData: “@import ‘@/sass/variables.sass'”,
After that, things were cooking along great. Nice post, and thanks for being entertaining as you document. 🙂
Thanks for catching that! In my code it was a backtick and the Markdown changed it to those tags. Glad this helped!!
Thank you for this excellent and entertaining write up, it helped me a lot setting things up today !
A couple of remarks:
– You may want to remove the `
` tags from `.storybook/preview.js` at line 53 (markdown struck again)
- When using scss, I had to add a semi after the `@import '@/sass/variables.scss'` directive
The last part I'm struggling with is getting the preview to show the font I'm configuring in the variables.scss file:
```
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
$body-font-family: 'Open Sans', sans-serif;
$heading-font-family: "Open Sans", sans-serif;
```
Even though I added the preview-head.html file with the Google Font link, vuetify still uses Roboto, as if my variables wasn't picked up. Any clue to point me in the correct direction ?
Thanks for the note! Glad this helped. I think I finally fixed the issue with displaying backticks in the code section. I think the reason you needed the semicolon is a difference between SASS and SCSS syntax, which is expected. As for getting your fonts to show, first obvious thing to check is to make sure all your filenames and paths are correct. The SASS/SCSS import is probably the trickiest part of all of this. I did a lot of experimenting before I got it to work. Lastly, in a more recent project I moved the instantiation of vuetify in preview.js outside of the decorator.
Hi Morgan,
Great article
I tried running your project/config and I’m still getting errors.
Can you publish/send/advise about the specific versions that you used as I’m getting errors related exporting the main.js config.
Thanks in advance,
Dror
I just checked my last working version and it appears to be v6.1.11 of all of the storybook-related plugins. Also, as noted, I ran into problems when trying to install with npm@7 and had to go back to using npm@6
Great! Thank you so much!
Hi Morgan,
Thanks for this article, It helped me a lot! I was curious if you where also able to integrate vue-i18n in this setup, I haven’t figured out how to do this in V6.x:
import VueI18n from ‘vue-i18n’
Vue.use(VueI18n)
return Vue.extend({
router,
store,
vuetify: new Vuetify(options),
i18n,
components: { wrapped },
….
same for:
export const decorators = [() => ({
template: ”,
i18n,
})]
Both work, but it doesn’t seem to be correct, often I get: Error in render: “TypeError: Cannot read property ‘_t’ of undefined” in the console.
I was curious if you maybe had figured it out?
Thanks in advance,
Stevie
Stevie, did you ever figure this out? I see i18n info in the post and I can’t remember now if I added that originally or if I did it in response to your question.
Thanks Morgan for the setup guide.
Regarding the `sass` part, if anyone want to use `scss` for the variables. Slightly modify the config module in `main.js`
“`js
{
test: /\.s(c|a)ss$/,
use: [
‘vue-style-loader’,
‘css-loader’,
{
loader: ‘sass-loader’,
options: {
implementation: require(‘sass’)
}
}
]
}
“`
Thanks, Sai!! Yes, it’s confusing and annoying that switching between SASS/SCSS requires this kind of config change. Much appreciated!!
What does your i18n.ts file look like inside of src/plugins I am having the same issue
Hi Chantelle! First off, my i18n config is inside `src/i18n.js` and it looks like:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
function loadLocaleMessages () {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key)
}
})
return messages
}
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
messages: loadLocaleMessages(),
})