美文网首页
create react app 如何通过 storybook

create react app 如何通过 storybook

作者: 莫帆海氵 | 来源:发表于2021-11-14 13:39 被阅读0次

目的

希望能生成如下要求的文档,能便于组件的使用

  • 能实时渲染组件
  • 能查看代码示例
  • 能查看组件的参数说明
  • 列举组件的常用示例

环境

  • react@16.8
  • creat-react-app@4+
  • storybook@6.3
  • webpack@4+

安装

// 初始化
npx sb init

// 启动
npm run storybook

// 打包
npm run build-storybook

安装后会生成 .storybook 和 src/stories 的文件

  • .storybook/main.js 编译的配置
  • .storybook/preview.js 工具、插件等的配置
  • src/stories 默认的示例

配置

main.js

在基于 create-react-app 生成的项目中需要处理 webpack 配置

// main.js 所有配置项
{
    "stories": [] // 匹配 story 文档的规则
    "addons": [], // 所有的插件列表
    "webpackFinal": (config) => {}, // 可以扩展默认的 webpack 配置
    "babel": (options) => {} // 可以扩展默认的 bebel 配置
}
// ./.storybook/main.js
const webpackConfig = require("../config/webpack.config.dev.js")

module.exports = {
  stories: [
    // "../src/stories/*.stories.mdx",
    // "../src/stories/*.stories.@(js|jsx|ts|tsx)",
    "../src/components/**/*.stories.mdx",
    "../src/components/**/*.stories.js",
  ],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  webpackFinal: config => {
    // 移除默认的 css loader 规则
    config.module.rules.splice(7, 1)
    removeWebpackDefaultFileLoader(webpackConfig)

    let newConfig = {
      ...config,
      module: {
        ...config.module,
        rules: [...config.module.rules, ...webpackConfig.module.rules],
      },
    }

    // console.log("old config", newConfig.module)
    return newConfig
  },
  babel: async options => {
    // console.log(options.plugins)
    // 不返回值,默认使用 package.json 里的 babel 配置
  },
}

// 配置文件参见 webpack.dll.config.js
// 移除默认的 file loader
function removeWebpackDefaultFileLoader(webpackConfig) {
  webpackConfig.module.rules.forEach(rule => {
    const oneKey = "oneOf"
    if (Reflect.has(rule, oneKey)) {
      rule[oneKey].splice(rule[oneKey].length - 1, 1)
    }
  })
}

// package.json bebel 配置
"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      "@babel/plugin-proposal-optional-chaining",
      "@babel/plugin-proposal-class-properties",
      [
        "import",
        {
          "libraryName": "antd-mobile",
          "style": "css"
        }
      ]
    ]
}

preview.js

可以设置全局默认的 parameter、decorator、loader、全局变量 等等

// 设置默认的主题
export const parameters = {
  docs: {
    theme: themes.light
  }
}

preview-head.html

用于在 preview 页面头部追加一些通用的内容

// 设置 rem 默认字体大小,重置 sb 的一些样式
<style>
  html {
    font-size: 26.6667vw;
  }

  /* reset story book style */
  .sb-show-main.sb-main-padded {
    padding: 16px;
  }

  .sbdocs-wrapper {
    padding-top: 64px !important;
    padding-bottom: 64px !important;
  }
</style>

名词

  • story
  • component
  • CSF
  • Args
  • Parameters
  • Decorators
  • Loaders
  • DocsPage
  • MDX
  • Controls
  • Actions

story

story 是描述如何渲染一个组件的函数,可以说是文档的最小结构

component

同一个组件的不同状态渲染(story),都包含在一个 componet 下

Args

定义 story 的参数,Story Args and Component Args

Parameters

关于 story 静态的命名的元数据,用来控制功能和插件,eg:parameters.backgrounds 用来控制工具栏插件的背景颜色

Decorators

可以在 story 外面包裹自定义的 dom 结构,方便定义 story 渲染

Loaders

Loaders 是一个用来给 story 加载数据的异步函数,比如从远程接口获取 story 渲染需要的数据

DocsPage

自动生成包含所有 stories 文档,基于 addon-docs 插件

CSF

Component Story Format 缩写,是指用 js 形式来定义 story 的语法格式

MDX

新的文件格式,包含 MarkDown 和 JSX,

Controls

图形化界面用来控制 story 渲染的状态,通过 Args 和 ArgsType 定义

Actions

用来显示 story 事件回调接收的数据

如何写

// FloatBoard.stories.js

import React from 'react'
import FloatBoard from './float_board'

// component parameter 组件的描述和属性
export default {
    title: 'FloatBoard'
    component: FloatBoard
}

// story
export const FB1 = (args) => <FloatBoard {...args} />

// actions
FB1.args = {
    primary: 1
}
FB1.argTypes = {
    type: {
        otions: ['primary', 'secondary'],
        control: 'select'
    }
}
// FloatBoard.stories.mdx

import React from 'react'
import { Meta, Canvas, Story} from '@storybook/docs'
import FloatBoard from './float_board'

// component parameter 组件的描述和属性
<Meta
    title='FloatBoard'
    component={FloatBoard}
/>

// story
<Canvas>
    <Story name="Base FloatBoard">
        <FloatBoard ... />
    </Story>
</Canvas>

MDX 的示例

import { Meta, Story, ArgsTable } from "@storybook/addon-docs"
import FloatBoard from "./index"
import Preview from "mt-docs/preview"
import { utils } from "common"
const floatData = {
    bg_url: "http://f.mengtuiapp.com/common/share_150x150.png",
    click_type: 0,
    deadline: Date.now()/1000 + 12*60*60,
    h5_popup: true,
    link: "xxx",
    on: true,
    position: 0,
    scale: 0,
    subtitle: "subtitle",
    ticktock: 2,
    ticktock_bg_url: "http://f.mengtuiapp.com/common/share_150x150.png",
    title: "title",
    toast: "toast",
    // swagger里未找到time的定义,无此参数倒计时不会显示
    time: 0,
}
const scope = { floatData, FloatBoard }
const code = `
  <FloatBoard
      floatBoard={floatData}
  />
`

<Meta title="FloatBoard" component={FloatBoard} />

# FloatBoard

优惠券悬浮窗

## 基本功能

<Story name="基础用法" args={{floatBoard: floatData}}>
  {(args) => <FloatBoard {...args} />}
</Story>

## Props

<ArgsTable story="基础用法" />

CSF 的示例

import React from 'react'
import FloatBoard from './index'

const floatData = {
  bg_url: "http://f.mengtuiapp.com/common/share_150x150.png",
  click_type: 0,
  deadline: Date.now()/1000 + 12*60*60,
  h5_popup: true,
  link: "xxx",
  on: true,
  position: 0,
  scale: 0,
  subtitle: "subtitle",
  ticktock: 2,
  ticktock_bg_url: "http://f.mengtuiapp.com/common/share_150x150.png",
  title: "title",
  toast: "toast",
}

export default {
  title: 'FloatBoard',
  component: FloatBoard
}

export const MyFloatBoard = (args) => <FloatBoard {...args} />

MyFloatBoard.args = {
  floatData
}

ArgsTable

归属于 addon-docs 插件,用来展示 ArgTypes 定义的属性列表,表格形式展示。使用 addon-docs 插件会默认给每个 sotry 生成一组 ArgTypes,它是从组件定义的 propTypes 和 defaultProps 获取,不论类组件、函数组件、高阶组件都可以生成。

用法

// MDX 形式

// 直接用于组件上,显示指定组件的属性
import ComponentA from 'xxx'
<ArgsTable of={ComponentA} />


// 用于 story 上,显示对应组件的属性
<Story name="mystory">
    <ComponentA />
</Story>
<ArgsTable story="mysotry" />

'loose' mode configuration must be the same...

Error: .storybook/preview.js-generated-config-entry.js: 'loose' mode configuration must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled).

遇到的问题是在一个已有的 bebel 配置的项目加入 storybook,项目原有的 babel 配置和 storybook 默认的不一致,比如 plugin-proposal-class-properties 插件,它默认 option.loose=false,和默认 sb 的 babel 配置不一致。

需要确保 storybook 默认的 babel 配置和项目的是一致,修改 sb 的 babel 配置(plugins & presets) loose=false 即可。

// 原项目默认 babel plugin 配置
[
  "@babel/plugin-proposal-optional-chaining",
  "@babel/plugin-proposal-class-properties",
  [
    "import",
    {
      "libraryName": "antd-mobile",
      "style": "css"
    }
  ]
]
// sb 默认的 babel preset 配置
[
  [
    '@storybook/core-common/node_modules/@babel/preset-env',
    { shippedProposals: true, loose: true }
  ],
  '@storybook/core-common/node_modules/@babel/preset-typescript',
  [
    '@storybook/react/node_modules/@babel/preset-react',
    {}
  ],
  '@babel/preset-flow'
]

// sb 默认的 babel plugin 配置

[
  '@babel/plugin-transform-shorthand-properties',
  '@babel/plugin-transform-block-scoping',
  [
    '@babel/plugin-proposal-decorators',
    { legacy: true }
  ],
  [
    '@babel/plugin-proposal-class-properties',
    { loose: true }
  ],
  [
    '@babel/plugin-proposal-private-methods',
    { loose: true }
  ],
  '@babel/plugin-proposal-export-default-from',
  '@babel/plugin-syntax-dynamic-import',
  [
    '@babel/plugin-proposal-object-rest-spread',
    { loose: true, useBuiltIns: true }
  ],
  '@babel/plugin-transform-classes',
  '@babel/plugin-transform-arrow-functions',
  '@babel/plugin-transform-parameters',
  '@babel/plugin-transform-destructuring',
  '@babel/plugin-transform-spread',
  '@babel/plugin-transform-for-of',
  'babel-plugin-macros/dist/index.js',
  '@babel/plugin-proposal-optional-chaining',
  '@babel/plugin-proposal-nullish-coalescing-operator',
  [
    'babel-plugin-polyfill-corejs3',
    {
      method: 'usage-global',
      absoluteImports: 'core-js',
      version: '3.18.3'
    }
  ],
  'babel-plugin-add-react-displayname'
]

相关文章

网友评论

      本文标题:create react app 如何通过 storybook

      本文链接:https://www.haomeiwen.com/subject/zyxyaltx.html