10

This article is translated from the official website of personal understanding and interpretation of the technology. It is inevitable that there are some inappropriate points. We hope that you can give us more advice and learn together.

react-styleguidist will display all components on a page of the browser, including props documents, usage examples, and an environment for independent development of components. In Styleguidist, you can write examples in Markdown, and each code segment will be presented immediately;

principle

Styleguidist will load the components and use react-docgen to generate documentation. You may need to change the code to work properly.

React-docgen will read the component as a static text file, and then find the component (such as class or function declaration) similar to the pattern of finding React components. React-docgen does not run any JavaScript code, so if the component is dynamically generated, or packaged in a high-level component, or split into multiple files, react-docgen may not be able to understand it.

  • React-docgen supports components defined by React.createClass, ES6 classes and function components;
  • React-docgen supports Flow and TypeScript comments;

In some cases, the two components can be derived by deception Styleguidist and react-docgen:

  • Basic components exported as named
  • Enhanced components exported as default
import React from 'react'
import CSSModules from 'react-css-modules'
import styles from './Button.css'

// Base component will be used by react-docgen to generate documentation
export function Button({ color, size, children }) {
  /* ... */
}

// Enhanced component will be used when you write <Button /> in your example files
export default CSSModules(Button, styles)

begin

Install Styleguidist:

// npm
npm install --save react-styleguidist

// yarn
yarn add react-styleguidist

Configure package.json script

"scripts": {
  "styleguide": "NODE_ENV=development styleguidist server",
  "styleguide:build": "NODE_ENV=production styleguidist build",
}

Run Styleguidist

npm run styleguide  //启动styleguidist开发服务器
npm run styleguide:build  //构建生产HTML版本

Component generation documentation

Styleguidist generates documentation for the component based on the comments in the component, the propTypes declaration and Readerme.md

Parse props

default behavior: Styleguidist obtains props from propType s to generate a table, and displays the description of the component according to the comment of props, and obtains the default value of props according to defaultProps.

import React from 'react'
import PropTypes from 'prop-types'
/**
 * General component description in JSDoc format. Markdown is    *supported*.
 */
export default class Button extends React.Component {
  static propTypes = {
    /** Description of prop "foo". */
    foo: PropTypes.number,
    /** Description of prop "baz". */
    baz: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
  }

  static defaultProps = {
    foo: 42
  }

  render() {
    /* ... */
  }
}

Modify the default behavior

You can use propsParser and resolver change the default behavior of parsing props;

propsParser: Function
This method can reconstruct how to parse props from the source file. The default is to use react-docgen for parsing.

module.exports = {
  propsParser(filePath, source, resolver, handlers) {
    return require('react-docgen').parse(source, resolver, handlers)
  }
}

resolver
This method can determine which classes/components need to be resolved. The default behavior is to find all exported components in each file, and it can be configured so that all found components use a custom resolution method.

module.exports = {
  resolver: require('react-docgen').resolver
    .findAllComponentDefinitions
}
The PropType and documentation comments of the component are parsed by the react-docgen library and can be modified using the updateDocs function.
For more information on parsing props, see the react-docgen documentation.

Sample file search and writing

default behavior of Readme.md or [ComponentName].md files in the component folder by default and generates sample files.

Code blocks marked with js, jsx or javascript will be rendered as React components with interactive. For backward compatibility, code blocks without language tags will also be displayed as interactive React components.

React component example:

​```js
<Button size="large">Push Me</Button>
​```

You can add a custom props to an example wrapper:

​```js { "props": { "className": "checks" } }
<Button>I’m transparent!</Button>
​```

To render an example as highlighted source code add a `static` modifier:

​```jsx static
import React from 'react';
​```

Modify the default behavior

The md file name can be getExampleFilename . This method returns the new md file path through the provided component file path.

ComponentName.examples.md with Readme.md :

module.exports = {
  getExampleFilename(componentPath) {
    return componentPath.replace(/\.jsx?$/, '.examples.md')
  }
}

Associate other sample files

You can use the @example doclet syntax to associate other sample files with the component.

The Button component has an example loaded from the extra.examples.md file:

/**
 * Component is described here.
 *
 * @example ./extra.examples.md
 */
export default class Button extends React.Component {
  // ...
}

Write code

  • Import dependencies: import via import
  • Manage state: Each example is a function component, and you can use useState Hook to handle state.
// ```jsx inside Markdown
import React from 'react'
import Button from 'rsg-example/components/Button'
import Placeholder from 'rsg-example/components/Placeholder'
;<Button size="large">Push Me</Button>


// ```jsx inside Markdown
const [isOpen, setIsOpen] = React.useState(false)
;<div>
  <button onClick={() => setIsOpen(true)}>Open</button>
  <Modal isOpen={isOpen}>
    <h1>Hallo!</h1>
    <button onClick={() => setIsOpen(false)}>Close</button>
  </Modal>
</div>

moduleAliases
Define the alias of the module, you can import these aliases in the sample file to make the sample code more practical and reproducible;

const path = require('path');

module.exports = {
  moduleAliases: {
    'rsg-example': path.resolve(__dirname, 'src')
  }
}
  • Markdown syntax is supported;
  • If you need to display some JavaScript code that you don't want to be rendered interactive in the document, you can use the static modifier with the language tag;
  • Styleguidist Bublé , most ES6 functions are supported;
  • The rsg-example module is an alias defined by the moduleAliases option;
  • If you need a more complex presentation, it is usually best to define it in a separate JavaScript file and then import it into Markdown

Public method

By default, any methods of the component are considered private methods and will not be published. Using the JSDoc @public marking method, you can make it a public method and will be published in the document.

/**
 * @param {string} name
 * @public
 */
getName(name) {
  // ...
}

Hide props

By default, all props of the component are public and publishable. In some cases, there are certain props in the code, and you hope that this props will not be displayed in the document. JSDoc @ignore , and you can delete it from the document.

Button.propTypes = {
  /**
   * A prop that should not be visible in the documentation.
   * @ignore
   */
  hiddenProp: React.PropTypes.string
}

Positioning components

Find components

By default, Styleguidist will use this mode to locate components: src/components/**/*.{js,jsx,ts,tsx} .

E.g:

  • src/components/Button.js
  • src/components/Button/Button.js
  • src/components/Button/index.js

But the tests file will be ignored:

  • __tests__ folder
  • The file name contains .test.js or .spec.js (similar to: .jsx , .ts , .tsx )

Modify the default search method

The configuration components in the styleguide.config.js file can modify the component search method to adapt to different projects;

For example: if the component path is components/Button/Button.js , in order to simplify the import, export again components/Button/index.js export { default } from './Button' ), [In order to let components/Button replace components/Button/Button ], you need to skip index.js at this time.

module.exports = {
  components: 'src/components/**/[A-Z]*.js'
}

Use ignore to exclude certain files from the style guide

ignore:String[]
Defaults:

['**/__tests__/**', '**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/*.d.ts']

Use getComponentPathLine change the component import path

getComponentPathLine: Function
Default value: component file name;
Return value: return component path;

For example: Import Button components/Button components/Button /Button.js

const path = require('path');
module.exports = {
  getComponentPathLine(componentPath) {
    const name = path.basename(componentPath, '.js')
    const dir = path.dirname(componentPath)
    return `import ${name} from '${dir}';`
  }
}
All paths are relative to the config folder;

Load components

Styleguidist loads components and exposes them globally for use in examples.

Identifier

Styleguidist uses the displayName of the component as the identifier by default. If it cannot understand displayName (displayName is dynamically generated), it will fall back to what it can understand.

Sections

Sections: Array[{}]
Group components or add additional Markdown documents to the style guide.

Each attribute value of the Sections array is as follows:

Attribute namedescription
nameSections title
contentThe location of the Markdown file containing the overview content
componentsIt can be a glob pattern string, a component path array, a glob pattern string array, a function that returns a component array, or a function that returns a glob pattern string. The rules are the same as the components
sectionsNested Sections array (can be nested)
descriptionsection description
sectionDepthThe number of sections on a single page, only available in pagePerSection
exampleModeThe initial state of the code example, using exampleMode
usageModeThe initial state of props and methods, using usageMode
ignoreThe file to be ignored, the value can be a string or an array;
hrefNavigate URL (not the URL to navigate to the Sections content)
externalIf set, a new page will open
expandWhen setting tocMode to collapse (folded) in the general settings, confirm whether it should be unfolded;
  • All the above fields are optional;
// styleguide.config.js

module.exports = {
  sections: [
    {
      name: 'Introduction',
      content: 'docs/introduction.md'
    },
    {
      name: 'Documentation',
      sections: [
        {
          name: 'Installation',
          content: 'docs/installation.md',
          description: 'The description for the installation section'
        },
        {
          name: 'Configuration',
          content: 'docs/configuration.md'
        },
        {
          name: 'Live Demo',
          external: true,
          href: 'http://example.com'
        }
      ]
    },
    {
      name: 'UI Components',
      content: 'docs/ui.md',
      components: 'lib/components/ui/*.js',
      exampleMode: 'expand', // 'hide' | 'collapse' | 'expand'
      usageMode: 'expand' // 'hide' | 'collapse' | 'expand'
    }
  ]
}

Configure webpack

Styleguidist relies on webpack and uses webpack to determine how to load the project's files, but the project does not necessarily have to configure webpack.
By default, Styleguidist will look for webpack.config.js in the root directory of the project and use it.

Custom Webpack configuration

If webpack is configured in another location, you need to load it manually:

module.exports = {
  webpackConfig: require('./configs/webpack.js')
}

You can also merge multiple webpack configurations:

module.exports = {
  webpackConfig: Object.assign({}, require('./configs/webpack.js'), {
    /* Custom config options */
  })
}
  • Configurations entry , externals , output , watch , and stats will be ignored. In production, devtoo will also be ignored;
  • Plug-ins CommonsChunkPlugins , HtmlWebpackPlugin , MiniHtmlWebpackPlugin , UglifyJsPlugin , TerserPlugin , HotModuleReplacementPlugin will be ignored, because Styleguidist has already introduced them, and their re-introduction will affect Styleguidist;
  • If loaders do not work, try to include and exclude absolute paths;

styleguide configuration properties

Attribute nameTypes ofmeaning
titleStringSet page title
serverPortNumberThe port number
requireArrayAdd user-defined js, CSS or polyfills
assetsDirStringResource file name
styleguideDirStringDefine the folder of static HTML generated by the styleguidist build command; default value: styleguide
getComponentPathLineFunctionGet component loading path
templateObject / FunctionChange the HTML of the application. You can add favicon, meta tags, objects with embedded JavaScript or CSS.
stylesObject / String / FunctionCustomize the style of the Styleguidist sample component; the configuration file path is a relative configuration file or an absolute path.
themeObject / StringCustomize the UI fonts, colors, etc. of the Styleguidist sample component; the configuration file path is a relative configuration file or an absolute path.
sectionsArray[{}]Set component grouping
styleguideComponentsObjectRewrite the styleguide React component that is used to render to the browser;
webpackConfigObject / StringCustom webpack configuration;
For more configuration options, see the official document: configuration

use

How to hide a component in the style guide, which can be used in the example?

Through the skipComponentsWithoutExample attribute, do not add sample files for components that need to be ignored (the default is Readme.md).

skipComponentsWithoutExample: Boolean
Default value: false
Ignore this component if there is no sample file; unless require , other samples cannot access these components.

In an example to reference the ignored component:

// /Readme.md

// ```jsx 
import Button from '../common/Button'
;<Button>Push Me Tender</Button>

Ignored components can be used in all examples:

// styleguide.config.js
module.exports = {
  require: [path.resolve(__dirname, 'styleguide/setup.js')]
}

// styleguide/setup.js
import Button from './src/components/common/Button'
global.Button = Button

Each example does not introduce Button components, Button components can also be used;

How to change the layout of the style guide?

Any Styleguidist React component can be replaced.
In most cases, only the *Renderer components need to be replaced-all HTML is rendered by these components. View all available components
Sometimes the component wrapper Wrapper component is also modified-each example component is packaged. children is rendered as-is, but you can use it to provide custom logic rendering children .

Replace Wrapper

To replace the default Wrapper component, use react-intl's IntlProvider instead:

It is not possible to wrap the entire style guide because each example is compiled separately in the browser.
// styleguide.config.js
const path = require('path');

module.exports = {
  styleguideComponents: {
    Wrapper: path.join(__dirname, 'src/styleguide/Wrapper')
  }
}
// src/styleguide/Wrapper.js
import React, { Component } from 'react';
import { IntlProvider } from 'react-intl';

export default class Wrapper extends Component {
  render() {
    return (
      <IntlProvider locale="en">{this.props.children}</IntlProvider>
    )
  }
}

Replace StyleGuideRenderer

const path = require('path')
module.exports = {
  styleguideComponents: {
    StyleGuideRenderer: path.join(
      __dirname,
      'src/styleguide/StyleGuideRenderer'
    )
  }
}
// src/styleguide/StyleGuideRenderer.js
import React from 'react'
const StyleGuideRenderer = ({
  title,
  version,
  homepageUrl,
  components,
  toc,
  hasSidebar
}) => (
  <div className="root">
    <h1>{title}</h1>
    {version && <h2>{version}</h2>}
    <main className="wrapper">
      <div className="content">
        {components}
        <footer className="footer">
          <Markdown
            text={`Created with [React Styleguidist](${homepageUrl})`}
          />
        </footer>
      </div>
      {hasSidebar && <div className="sidebar">{toc}</div>}
    </main>
  </div>
)

How to change the style of the style guide?

There are two properties to change the style of the style guide: theme and styles.

  • theme: You can change the font, color, etc.
  • styles: You can adjust the style of any Styleguidist component;
// styleguide.config.js
module.exports = {
  theme: {
    color: {
      link: 'firebrick',
      linkHover: 'salmon'
    },
    fontFamily: {
      base: '"Comic Sans MS", "Comic Sans", cursive'
    }
  },
  styles: {
    Logo: {
      // the LogoRenderer component
      logo: {
        animation: '$blink ease-in-out 300ms infinite'
      },
      '@keyframes blink': {
        to: { opacity: 0 }
      }
    }
  }
}

can store the object values of theme and styles in separate files, and introduce the file path in the configuration file, which allows hot module replacement (HMR).
Every time you modify theme.js or styles.js, HMR will be triggered to update the styleguide in the browser.

The same example above will be converted to:

// styleguide.config.js
module.exports = {
  // ...
  styles: './styleguide/styles.js',
  theme: './styleguide/themes.js'
}
// ./styleguide/theme.js
module.exports = {
  color: {
    link: 'firebrick',
    linkHover: 'salmon'
  },
  fontFamily: {
    base: '"Comic Sans MS", "Comic Sans", cursive'
  }
}
// ./styleguide/styles.js
module.exports = {
  Logo: {
    // the LogoRenderer component
    logo: {
      animation: '$blink ease-in-out 300ms infinite'
    },
    '@keyframes blink': {
      to: { opacity: 0 }
    }
  }
}

How to add global styles to components?

StyleGuide in the form of jss-global api through 06087f4d55d7a1 attribute.

This method does not set the style on the style guide UI.
// styleguide.config.js
module.exports = {
  components: 'src/components/**/[A-Z]*.js',
  styles: {
    StyleGuide: {
      '@global body': {
        fontFamily: 'Helvetica',
        fontWeight: bold,
      }
    }
  }
}

Is equivalent to:

body {
  font-family: 'Helvetica';
  font-weight: bold,
}

How to add custom JavaScript, CSS, polyfill?

Use the require attribute:

// styleguide.config.js
const path = require('path');

module.exports = {
  require: [
    'babel-polyfill',
    path.join(__dirname, 'path/to/script.js'),
    path.join(__dirname, 'path/to/styles.css')
  ]
}

How to add external JavaScript and CSS files?

Use the template attribute.

template
Change the HTML of the style guide. The attribute value supports two types: Object and Function.

// styleguide.config.js
module.exports = {
  template: {
    head: {
      scripts: [
        {
          src: 'assets/js/babelHelpers.min.js'
        }
      ],
      links: [
        {
          rel: 'stylesheet',
          href: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css'
        }
      ]
    }
  }
}
Compared with the require attribute, the scripts and links configured in the template run in the browser, not during the webpack build process. This is useful for scripts where components produce side effects. In this case, Babel output needs to be functional.

How to use CSS animation in the style guide?

Due to the scope of internal keyframes, the animation property in CSS rules does not directly use the name of its keyframe animation. If you use CSS animation, you must define its key frame at the root of the renderer object.

// styleguide.config.js
module.exports = {
  styles: {
    // the LogoRenderer component
    Logo: {
      '@keyframes blink': {
        to: { opacity: 0 }
      }
    }
  }
}

How to add fonts from Google Fonts?

Use template and theme attributes:

// styleguide.config.js
module.exports = {
  template: {
    head: {
      links: [
        {
          rel: 'stylesheet',
          href: 'https://fonts.googleapis.com/css?family=Roboto'
        }
      ]
    }
  },
  theme: {
    fontFamily: {
      base: '"Roboto", sans-serif'
    }
  }
}

How to use ref in the example?

Use ref props as functions and assign parameters to local variables:

// Button/Readme.md
const [value, setValue] = React.useState('')
let textareaRef
;<div>
  <Button onClick={() => textareaRef.insertAtCursor('Pizza')}>
    Insert
  </Button>
  <Textarea
    value={value}
    onChange={e lili=> setValue(e.target.value)}
    ref={ref => (textareaRef = ref)}
  />
</div>

时倾
794 声望2.4k 粉丝

把梦想放在心中