<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Scalingo</title>
    <description>The latest articles on DEV Community by Scalingo (@scalingo).</description>
    <link>https://dev.to/scalingo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4067%2Fd2804125-c14d-49b3-8121-bfef6817e297.png</url>
      <title>DEV Community: Scalingo</title>
      <link>https://dev.to/scalingo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scalingo"/>
    <language>en</language>
    <item>
      <title>4 tips to use Storybook in a Vue project</title>
      <dc:creator>Cyrille</dc:creator>
      <pubDate>Tue, 01 Jun 2021 15:44:13 +0000</pubDate>
      <link>https://dev.to/scalingo/4-tips-to-use-storybook-in-a-vue-project-3kb4</link>
      <guid>https://dev.to/scalingo/4-tips-to-use-storybook-in-a-vue-project-3kb4</guid>
      <description>&lt;p&gt;At &lt;a href="https://scalingo.com/" rel="noopener noreferrer"&gt;Scalingo&lt;/a&gt; we are a Platform as a Service and we recently revamp the dashboard used by all our clients.&lt;br&gt;
We were able to speed up our development process thanks to &lt;/p&gt;

&lt;p&gt;Today I'll share our best tips and tricks to use Storybook in a Vue project.&lt;/p&gt;

&lt;p&gt;This article was initially published on Scalingo.com. You can find the full article &lt;a href="https://scalingo.com/blog/guide-storybook-vue-js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tip 1 : Use js format, not mdx
&lt;/h3&gt;

&lt;p&gt;Storybook offers two stories formats: js and &lt;a href="https://mdxjs.com/" rel="noopener noreferrer"&gt;mdx&lt;/a&gt; (mdx are md files, with the ability to have js sections). We initially picked the mdx format for its improved documentation capabilities. Turn out it was bad idea.&lt;/p&gt;

&lt;p&gt;Indeed we did not use the mdx extra features and maintenance with mdx is particularly harder.&lt;/p&gt;

&lt;p&gt;It was better to have separate md files for the few points we wanted to document and to use the “more standard” js format. The reason is, especially with Vue.js, you will have less bugs and more documentation online with the js format.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tip 2: VueDevTools in Storybook (quick hack)
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/vuejs/vue-devtools" rel="noopener noreferrer"&gt;VueDevTools&lt;/a&gt; does not work in canvas mode, but works if the canvas is open in a new tab (top left second icon).&lt;/p&gt;
&lt;h3&gt;
  
  
  Tip 3 : Separate concerns of your components (Controller/Views…)
&lt;/h3&gt;

&lt;p&gt;We made the choice to separate concerns of our components.&lt;/p&gt;

&lt;p&gt;Concretely, we have three components types: controllers, views, design system. Controllers components are the only one authorized to interact with model (services, store). Consequently, this allows us to have all others component as “pure” visual components, piloted only via “dumb” props.&lt;/p&gt;

&lt;p&gt;It leads to easy creation/update of complex views component, via dumb flat json files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/views/Projects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/stories/data/currentUser.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./props.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Views/Main/Apps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argTypes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argTypes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;Projects v-bind="$props"&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your component is already functional in a browser, you can use the VueDevTools/component tab to copy the props and paste them in the json file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1621237728-vuedevtools-component-tab.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1621237728-vuedevtools-component-tab.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1621237728-vuedevtools-component-tab.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 4 : Add StoriesWrapper around your stories
&lt;/h3&gt;

&lt;p&gt;There are at least two different reasons to add a wrapper around your stories.&lt;/p&gt;

&lt;p&gt;In our case we use nested routing. So the final view component is, in the real app, wrapped around N components. If you have a router, the view is at least wrapped in the App component. Stories wrapper is here to reproduce this “wrapped” environment.&lt;/p&gt;

&lt;p&gt;The second reason: the wrapper can also help you control finely the canvas parameters.&lt;/p&gt;

&lt;p&gt;Here our preview.js configuration, with our two additional toolbar menus “i18n” and “theme”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/storybook/preview.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globalTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18n selector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;toolbar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme selector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;toolbar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appSbProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Story&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;story/&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decorators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;appSbProvider&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And how we use it in our a child called in all our stories wrappers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/components/others/storybook/AppSb.vue&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AppSb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nf"&gt;created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is allowing us to mount “app like” view stories, without too much effort. And control them via the Storybook toolbar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The Storybook wrapper&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;WelcomeSb&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/others/storybook/WelcomeSb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// The component we want to storify&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/views/Projects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Flat Props in json files&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/stories/data/currentUser.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./props.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Views/Main/Apps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argTypes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argTypes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WelcomeSb&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;WelcomeSb selectedRoute="Projects"&amp;gt;&amp;lt;Projects v-bind="$props"&amp;gt;&amp;lt;/Projects&amp;gt;&amp;lt;/WelcomeSb&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Here are 4 tips from Scalingo as we are heavy users of Storybook!&lt;/p&gt;

&lt;p&gt;Feel free to check our full &lt;a href="https://scalingo.com/blog/guide-storybook-vue-js" rel="noopener noreferrer"&gt;guide about Storybook&lt;/a&gt; in a Vue.js project on our blog or the first part of this blog post on &lt;a href="https://dev.to/scalingo/storybook-in-a-vue-js-project-an-introduction-guide-4i9n"&gt;dev.to&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;And if you need hosting without having to handle servers, feel free to check us out!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>storybook</category>
    </item>
    <item>
      <title>Storybook in a Vue.js project: an Introduction Guide</title>
      <dc:creator>Cyrille</dc:creator>
      <pubDate>Wed, 19 May 2021 09:00:52 +0000</pubDate>
      <link>https://dev.to/scalingo/storybook-in-a-vue-js-project-an-introduction-guide-4i9n</link>
      <guid>https://dev.to/scalingo/storybook-in-a-vue-js-project-an-introduction-guide-4i9n</guid>
      <description>&lt;p&gt;Looking for a starting point about Storybook in a Vue.js project?&lt;/p&gt;

&lt;p&gt;Your are at the right place!&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://scalingo.com/" rel="noopener noreferrer"&gt;Scalingo&lt;/a&gt; we have been using and testing Storybook for a year while we were revamping the &lt;a href="https://dashboard.scalingo.com/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; used by our customers.&lt;/p&gt;

&lt;p&gt;We decided to write this &lt;strong&gt;guide for Storybook in a Vue.js project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will start by a quick reminder about Storybook before explaining different use cases. We will end up the article with tips and tricks of using Storybook in a Vue.js project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;To give you a bit of context, Scalingo is a european PaaS offering cloud hosting and aiming to build the best PaaS for developers of the world. I am Cyrille Colon Software engineer and tech lead at Scalingo.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Storybook?
&lt;/h2&gt;

&lt;p&gt;Let’s start by defining Storybook!&lt;/p&gt;

&lt;p&gt;This is taken from the &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook homepage&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Storybook is an open source tool for developing UI components and pages in isolation. It simplifies building, documenting, and testing UIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  An example of Storybook usage
&lt;/h3&gt;

&lt;p&gt;To understand why, let’s take an example.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to build an app, and this app needs buttons.&lt;/li&gt;
&lt;li&gt;You want to use a component oriented framework (we use Vue.js, but it could be another one).&lt;/li&gt;
&lt;li&gt;You code it into a “Button.vue” file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you will “storybook it”.&lt;/p&gt;

&lt;p&gt;That means that you create a storybook story around the component. For that you write the file below (a “story”, in storybook vocabulary).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Button from "@/components/molecules/buttons/Button"; // The component I want "storybook"
export default {
  title: "Molecules/ButtonDemo", // The story path
  component: Button, // The element the story is about
};
const Template = () =&amp;gt; ({
  components: { Button }, // Components available in the story template, just below
  template: `
    &amp;lt;div class="flex space-x-3 p-2"&amp;gt;
      &amp;lt;Button kind="regular"&amp;gt;Regular&amp;lt;/Button&amp;gt;
      &amp;lt;Button kind="primary"&amp;gt;Primary&amp;lt;/Button&amp;gt;
      &amp;lt;Button kind="warning"&amp;gt;Warning&amp;lt;/Button&amp;gt;
      &amp;lt;Button kind="danger"&amp;gt;Danger&amp;lt;/Button&amp;gt;
      &amp;lt;Button kind="neutral"&amp;gt;Neutral&amp;lt;/Button&amp;gt;
      &amp;lt;Button kind="empty"&amp;gt;Empty&amp;lt;/Button&amp;gt;
    &amp;lt;/div&amp;gt;
  `, // Let's use 6 variants of my button
}); // My variable "Template" will need to be bind to value before to become a story.
export const Default = Template.bind({}); // "default" will be the story name, and so, last path element
Default.args = {}; // Story args are for latter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;➡️ And this is what you will get on Storybook on your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807038-storybook-usage.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807038-storybook-usage.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807038-storybook-usage.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you use Storybook for Vue.js?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Storybook as developer documentation
&lt;/h3&gt;

&lt;p&gt;The first obvious Storybook use is for documentation. In &lt;a href="https://scalingo.com/" rel="noopener noreferrer"&gt;Scalingo&lt;/a&gt; we use it everyday for our internal documentation.&lt;/p&gt;

&lt;p&gt;It does an excellent job here: the search and the tree structure make it easy to find what you want or just to look exhaustively.&lt;/p&gt;

&lt;p&gt;Given its auto generated nature, it is always up to date, at &lt;strong&gt;no cost for anybody&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Storybook comes with whistle and bells about documentation: the &lt;a href="https://storybook.js.org/docs/react/writing-docs/introduction" rel="noopener noreferrer"&gt;docs tab&lt;/a&gt; and the &lt;a href="https://storybook.js.org/docs/react/essentials/controls" rel="noopener noreferrer"&gt;controls panels.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When they are marvelous at first glance, we did not find any practical usage for the controls panels. We ended up using the docs tab only to locate the story component/arguments visible in the canvas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807113-stories-on-storybook.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807113-stories-on-storybook.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807113-stories-on-storybook.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook as states simulators
&lt;/h3&gt;

&lt;p&gt;An other use for Storybook in Vue.js is using it as states simulators.&lt;/p&gt;

&lt;p&gt;Let’s imagine you have a table.&lt;/p&gt;

&lt;p&gt;The table can have several states by itself (initial, empty, few elements, paginated) and each row may have additional states (for example if the table contains “messages” they can be “sent”, “delayed”, “draft”, …). Some of these states are mutually exclusive.&lt;/p&gt;

&lt;p&gt;Storybook lets you see them all, at the cost of a single click (or less, if you put them together in a single story).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807240-storybook-as-states-simulator.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807240-storybook-as-states-simulator.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807240-storybook-as-states-simulator.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook as a communication tool
&lt;/h3&gt;

&lt;p&gt;An other usage of Storybook can be using it as a communication tool. This will be particularly useful for Product Owners.&lt;/p&gt;

&lt;p&gt;A storybook can be exported under the form of a static website.&lt;/p&gt;

&lt;p&gt;From here, it can be fully used by different persons “out of the box”.&lt;/p&gt;

&lt;p&gt;No API needed or even yarn &amp;amp; co.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807306-storybook-as-collaboration-project.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807306-storybook-as-collaboration-project.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807306-storybook-as-collaboration-project.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Product owners can easily navigate to an app feature and see all the states related. They can also copy paste links (storybook stories URLs) and/or annotate screenshots.&lt;/p&gt;

&lt;p&gt;This is very useful to bring together into an issue ticket and make it very descriptive with the Product Owner intent.&lt;/p&gt;

&lt;p&gt;Similarly, at Scalingo we asked an advice on design to somebody unfamiliar with the project. In a few minutes, the person was able to grasp our problem and offer solutions working in all app states.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook as automated visual tests source
&lt;/h3&gt;

&lt;p&gt;Via some tools - we use &lt;a href="https://loki.js.org/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt; - it is possible to add automation to a storybook. If you have done visual testing in the past, you may remember it can be quite painful.&lt;/p&gt;

&lt;p&gt;Visual testing is often very slow, but the worse problem is “flake”.&lt;/p&gt;

&lt;p&gt;Flaky tests are tests that sometimes pass, sometimes not, more or less randomly.&lt;/p&gt;

&lt;p&gt;Here storybook and Loki shine: the amount of flake we had is zero, even with CSS animations in some stories.&lt;/p&gt;

&lt;p&gt;Loki/Storybook is also quite fast (200 stories take 60 seconds) and the Loki diff mechanism makes it easy to spot what went wrong.&lt;/p&gt;

&lt;p&gt;For example in this case I made the circle more wide (the differences appear in pink in the difference image)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807435-storybook-example.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807435-storybook-example.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807435-storybook-example.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807441-storybook-example-2.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807441-storybook-example-2.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807441-storybook-example-2.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maintenance side, given you can review easily the differences via images and accept a new reference state via a single command line, it is a bliss.&lt;/p&gt;

&lt;p&gt;Visual tests really allow us to be confident during release or dependencies upgrade.&lt;/p&gt;

&lt;p&gt;Ideally, you want your visual testing automated into your CI.&lt;/p&gt;

&lt;p&gt;For information Storybook creators have also created &lt;a href="https://www.chromatic.com/" rel="noopener noreferrer"&gt;Chromatic&lt;/a&gt; which is a nice tool. Not only it runs the CI tests, but also has some features like serving storybooks or PR collaborations.&lt;/p&gt;

&lt;p&gt;We ended up not using it only because of this price. In our case it would have costed more than 2500 euros per developer each year - for only Chrome coverage.&lt;/p&gt;

&lt;p&gt;If you want a more complete coverage (3 browsers, 4 responsiveness modes, 2 themes), the price quickly adds up.&lt;/p&gt;

&lt;p&gt;Loki has a &lt;a href="https://loki.js.org/serverless.html" rel="noopener noreferrer"&gt;CI integration&lt;/a&gt;, but miles away from Chromatic (no dashboard to explore the build results, manual configuration, …).&lt;/p&gt;

&lt;p&gt;For the moment we just run Loki by hand before release - or at particular times (like deps upgrade). Then, we push the images into a PR request and use Github comparison tools (side by side, swipe, onion skin) to look at the differences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807500-loki-ci-integration.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.datocms-assets.com%2F36416%2F1620807500-loki-ci-integration.png%3Ffit%3Dcrop%26fm%3Djpg%26w%3D825" alt="https://www.datocms-assets.com/36416/1620807500-loki-ci-integration.png?fit=crop&amp;amp;fm=jpg&amp;amp;w=825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is working fine, while not - of course - being perfect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook as variants viewers
&lt;/h3&gt;

&lt;p&gt;Web apps targets are now larger than ever: very larges screens, mobiles, browsers, dark mode, …&lt;/p&gt;

&lt;p&gt;Storybook canvas can display components under different variants, via parameters.&lt;/p&gt;

&lt;p&gt;Out of the box, you will have the ability to change the canvas screen size, but you can code custom parameters. At Scalingo we added two to handle i18n and theming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is it for this introduction guide to Storybook! &lt;/p&gt;

&lt;p&gt;As you can read, Storybook has improved our process here at &lt;a href="https://scalingo.com/blog/guide-storybook-vue-js" rel="noopener noreferrer"&gt;Scalingo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next week I'll write an other article about our best Tips and Tricks to use Storybook in a vue project.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>storybook</category>
    </item>
  </channel>
</rss>
