vite、vue3和storybook

关于storybook

storybook是什么?

Storybook is a tool for UI development. It makes development faster and easier by isolating components. This allows you to work on one component at a time. You can develop entire UIs without needing to start up a complex dev stack, force certain data into your database, or navigate around your application.

storybook可以干什么?

  • 根据组件注释生成对应的文档信息
  • 根据组件prop类型自动生成对应类型的交互控制
  • 可以编写组件交互示例
  • 可以进行组件测试
  • etc

概览

image-20220118175711768

基于vite和vue3使用storybook

基本步骤

  1. 初始化storybook[1]

    1
    npx sb@next init --builder storybook-builder-vite
  2. 平移需要用到的vite配置到.storybook/main.js里面,其中viteFinal方法[2]就是专门设置自定义vite配置的地方,可以在这里修改或覆盖对应的配置,然后返回配置对象即可,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // ...

    module.exports = {
    // ...
    async viteFinal(config) {
    // 这里修改或覆盖配置
    config.resolve.alias = [
    {
    find: /^@\//,
    replacement: path.resolve(__dirname, '..', 'src') + '/'
    },
    {
    find: 'vue',
    replacement: 'vue/dist/vue.esm-bundler.js'
    }
    ]
    // ...
    return config
    }
    }
  3. 自定义storybook vite打包缓存目录,如果不自定义一个缓存目录,则会导致storybook和正常开发的vite项目共用同一个缓存目录,那么里面的文件很有可能就是相互覆盖,导致两边一启动就会重新pre-building

    1
    config.cacheDir = 'node_modules/.vite-storybook' // 避免跟开发环境一个缓存目录,以免相互覆盖;
  4. 如果组件中用到了一些和app实例相关的全局配置,那么同样地需要平移地把相应的配置在.storybook/preview.js(这个文件也可以用.ts)中,可以把这里当做storybook的入口文件:

    1
    import { app } from '@storybook/vue3'; // 这里的app就是storybook vue实例
  5. 上面的都配置好了之后,剩下的就是补充组件注释和增加对应组件的story文件了,最后yarn storybook就可以看到组件交互文档了;

关于组件注释

组件文档关心的地方无非就是老三样(propseventsslots)和组件自身的描述,只需要在对应的地方写上jsdoc风格的注释即可:

image-20220118162025797

image-20220118162144013

需要注意的是:

  1. 由于@storybook/vue3依赖的上游解析器vue-docgen-api还不支持emits这种事件类型的注释,所以events目前貌似无法通过注释来生成对应的描述;
  2. 同理,对于setup风格的vue文件支持度也要取决于vue-docgen-api
  3. slot注释需要增加@slot装饰符;

关于story文件

  • 文件格式:*.stories.@(js|jsx|ts|tsx|mdx);默认是这些格式,关于探测story文件的规则可以在.storybook/main.js进行配置;
  • 本质上一个story文件对应一个组件,然后里面的每一个story实例就是这个组件的一个交互示例;所以完全可以把一个story实例当做是对当前组件的props/events/slots的一种组合;

image-20220118163657467

image-20220118171107283

其他问题

无法正确解析props类型

当使用函数来输出prop定义信息时,会发现storybook得到的类型推断直接就是对应的代码,而非最终类型:

image-20220114163559656

这个可以理解,因为一般这种提取注释生成文档的工具都是从AST信息中进行获取的,如果AST推断得到的是一个函数节点当然就没法正确解析执行后的结果;目前解决思路有

  • 把这种函数当做宏,然后storybook在加载前把宏输出成结果字符串;其实利用rollup的虚拟文件玩法,这种思路是可以实现的[3]

  • 根据解析后的VNode信息来补充,因为Vue解析成VNode后其prop类型就是执行后的结果,即运行时真正用到的信息;

    image-20220114185734981

    当然这种方式得到的不是最准确的ts interface定义,因为在运行时这些类型都被分解成原子类型了(就是vue2中所熟悉的各种原始类型和数据结构的构造函数),不过至少能看;

和volar的冲突

如果你发现volar在推导template的组件类型突然全变成了any时,可能就是storybook的锅;

推荐解决方案:https://github.com/johnsoncodehk/volar/discussions/592#discussioncomment-1763880

自动化生成对应组件的story

如果你仅仅只想用storybook来快速查看组件文档,而不需要各种定制化的示例编写时,可以尝试用node脚本直接从一个story文件模板快速生成对应组件的story文件,省的一个个填写;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const template = `import ${name} from '@/components/${name}.vue';
import { basicTemplate, getComponentPropInfo } from './tool';

type ${name}Props = InstanceType<typeof ${name}>['$props'];

export default {
title: '业务组件/${name}',
component: ${name},
argTypes: getComponentPropInfo(${name}.props, ${name}['__docgenInfo']),
};

const Template = basicTemplate<${name}Props>(${name});

export const Basic = Template.bind({});
Basic.args = {};
Basic.storyName = '基本使用';
` // 一个包含空白参数story实例的story文件模板,仅供参考

这样就可以快速查看文档了;

更多

更多storybook的用法推荐看官方文档,真的是极其详细的文档;

用默认的webpack打包器

storybookvite版本目前还是测试阶段,所以如果用默认的webpack实际上也能用;关于这种用法也有很多坑,以下遇到的问题仅供参考:

  1. Error: PostCSS plugin tailwindcss requires PostCSS 8.javascript - Error: PostCSS plugin tailwindcss requires PostCSS 8 - Stack Overflow
  2. 编译成功后打开网址报错:CANNOT get /Storybook が CANNOT get / と表示された時 - Qiita
  3. 使用sass配置报错:Type Error: this.getOptions is not a function For style-loaderreactjs - Type Error: this.getOptions is not a function For style-loader - Stack Overflow
  4. webpack配置(因为storybook默认使用webpack4进行打包配置):https://storybook.js.org/docs/vue/configure/webpack#extending-storybooks-webpack-config

相关文章


  1. https://storybook.js.org/blog/storybook-for-vite/ ↩︎

  2. 在vite项目中使用storybook - 知乎 ↩︎

  3. typed-macro/DOCUMENTATION.md at master · typed-macro/typed-macro ↩︎