Adding Docs with Storybook

Now that you’re sharing our project with the world, you should think about taking the documentation to the next level. Storybook[79] has rapidly become a popular library for generating documentation pages for React components. Using Storybook, you can integrate live examples with all the information devs need to take full advantage of your components.

Getting Started with Storybook

Storybook has a handy script that you can run with npx to get started:

 $ ​​npx​​ ​​-p​​ ​​@storybook/[email protected]​​ ​​sb​​ ​​init

Once that script finishes, you’ll see that you have some new devDependencies:

 // package.json
 ...
 "devDependencies"​: {
 ...
 "@storybook/react"​: ​"^4.1.11"​,
 "@storybook/addon-actions"​: ​"^4.1.11"​,
 "@storybook/addon-links"​: ​"^4.1.11"​,
 "@storybook/addons"​: ​"^4.1.11"
 },
 ...

And two new scripts:

 // package.json
 ...
 "scripts"​: {
 ...
 "storybook"​: ​"start-storybook -p 6006"​,
 "build-storybook"​: ​"build-storybook"
 },
 ...

The script also added two new directories, .storybook and stories. The .storybook directory contains configuration, and the stories directory is where your documentation will live. The script generated some placeholder documentation in stories/index.stories.js.

Run the storybook script to start it up:

 $ ​​npm​​ ​​run​​ ​​storybook
 
 Storybook 4.1.11 started
 4.96 s for manager and 4.63 s for preview
 
 Local: http://localhost:6006/
 On your network: http://192.168.0.173:6006/

Under the hood, Storybook spun up a webpack server instance. Note that it’s using its own built-in configuration, not the webpack.config.js from the project root.

Open the link to see the Storybook page. (In VS Code, you can open links shown in the integrated terminal using -click on macOS, -click on Windows and Linux.) You should see a nice welcome screen in your browser with a handy link to the Storybook documentation on writing stories.[80]

To see the Carousel component on this page, replace the placeholder documentation in stories.index.js with your own:

 // stories/stories.index.js
 import​ React ​from​ ​'react'​;
 import​ { storiesOf } ​from​ ​'@storybook/react'​;
»import​ Carousel ​from​ ​'../src/Carousel'​;
»import​ slides ​from​ ​'../example/slides'​;
»
»storiesOf(​'Carousel'​, module).add(​'default'​, () => (
» <Carousel slides=​{​slides​}​ />
»));

Moments after you save that, the change should immediately appear in the browser. Storybook’s webpack server comes configured out of the box for hot module reloading (HMR), making updates very fast: the page receives the new JavaScript modules without having to refresh.

This is a good time for a commit:

 :wrench: Initial Storybook setup

Now you have a Storybook page that shows Carousel in action. But if that’s all there was to it, there wouldn’t be much reason to use Storybook instead of the project’s existing example server. So let’s find out what else Storybook can do!

Enhancing Stories with Addons

The magic of Storybook is its extensibility, in the form of assorted addons.[81] There are abundant options for making your documentation richer through these handy plugins.

Let’s start with the Actions addon. This will add a panel to the bottom of the page for reporting events. We’ll use it to display onIndexChange events. Start by installing the addon from npm:

 $ npm install --save-dev @storybook/[email protected]
 + @storybook/[email protected]

Then create a new file called .storybook/addons.js and add this line to register the new addon:

 // .storybook/addons.js
 import​ ​'@storybook/addon-actions/register'​;

The webpack server watches existing files for updates, but won’t recognize new files, so you’ll need to restart it before continuing.

Now add a bit of code to the Carousel story to tell the addon to listen for onIndexChange:

 // stories/index.stories.js
 import​ React ​from​ ​'react'​;
 import​ { storiesOf } ​from​ ​'@storybook/react'​;
»import​ { action } ​from​ ​'@storybook/addon-actions'​;
 import​ Carousel ​from​ ​'../src/Carousel'​;
 import​ slides ​from​ ​'../example/slides'​;
 
 storiesOf(​'Carousel'​, module).add(​'default'​, () => (
» <Carousel slides=​{​slides​}​ onIndexChange=​{​action(​'onIndexChange'​)​}​ />
 ));

With that change, you should see a new “Action Logger” panel at the bottom of the example page. Every time onIndexChange fires, either because you clicked the Prev/Next buttons or because the slides auto-advanced, the panel shows onIndexChange and the object that the listener received. It brings the API to life!

Let’s try one more addon: Knobs. This one provides controls so that people can adjust the example’s props directly from the page. We’ll use it to make autoAdvanceDelay customizable. Install it from npm:

 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​@storybook/[email protected]
 + @storybook/[email protected]

As with the Actions addon, Knobs requires you to register it:

 import​ ​'@storybook/addon-actions/register'​;
»import​ ​'@storybook/addon-knobs/register'​;

Then use it to create a numeric control that sets the autoAdvanceDelay prop:

 import​ React ​from​ ​'react'​;
 import​ { storiesOf } ​from​ ​'@storybook/react'​;
 import​ { action } ​from​ ​'@storybook/addon-actions'​;
»import​ { withKnobs, number } ​from​ ​'@storybook/addon-knobs'​;
 import​ Carousel ​from​ ​'../src/Carousel'​;
 import​ slides ​from​ ​'../example/slides'​;
 
 const​ stories = storiesOf(​'Carousel'​, module);
 
»stories.addDecorator(withKnobs);
 
 stories.add(​'default'​, () => (
» <Carousel
» autoAdvanceDelay={number(​'autoAdvanceDelay'​, 10e3)}
» slides={slides}
» onIndexChange={action(​'onIndexChange'​)}
»/​​>
 ));

Now the page should have a second panel containing an input that you can use to change how quickly slides auto-advance, as shown in the following screenshot. Set it to 200 for a frenetic, 5-slides-per-second experience. Set it to 0 to disable it entirely.

images/Storybook_with_knobs.png

Cool story, right? There’s just one more thing we’re going to do with it: publish!

Deploying to GitHub Pages

So far, we’ve been using Storybook in dev server mode. It’s time to put the project’s story on the web where the world can see it! Shut down the dev server, then make one change to package.json: add the args -o docs to the build-storybook script. This gives us our final package.json for the chapter:

 {
 "name"​: ​"test-driven-carousel"​,
 "version"​: ​"1.0.0"​,
 "description"​: ​""​,
 "main"​: ​"index.js"​,
 "scripts"​: {
 "test"​: ​"jest"​,
 "lint:js"​: ​"eslint . && prettier-eslint --list-different **/*.js"​,
 "lint:css"​: ​"stylelint **/*.js"​,
 "lint"​: ​"npm run lint:js && npm run lint:css"​,
 "format"​: ​"prettier-eslint --write **/*.js"​,
 "build"​: ​"webpack --config webpack.config.js"​,
 "dev"​: ​"webpack-dev-server --config webpack.config.js --open"​,
 "storybook"​: ​"start-storybook -p 6006"​,
»"build-storybook"​: ​"build-storybook -o docs"
  },
 "husky"​: {
 "hooks"​: {
 "pre-commit"​: ​"npm run lint"
  }
  },
 "keywords"​: [],
 "author"​: ​""​,
 "license"​: ​"ISC"​,
 "devDependencies"​: {
 "@babel/core"​: ​"^7.1.2"​,
 "@babel/plugin-proposal-class-properties"​: ​"^7.1.0"​,
 "@babel/preset-env"​: ​"^7.1.0"​,
 "@babel/preset-react"​: ​"^7.0.0"​,
 "@storybook/addon-actions"​: ​"^4.1.11"​,
 "@storybook/addon-info"​: ​"^4.1.11"​,
 "@storybook/addon-knobs"​: ​"^4.1.11"​,
 "@storybook/addon-links"​: ​"^4.1.11"​,
 "@storybook/react"​: ​"^4.1.11"​,
 "babel-core"​: ​"7.0.0-bridge.0"​,
 "babel-eslint"​: ​"^10.0.1"​,
 "babel-jest"​: ​"^23.6.0"​,
 "babel-loader"​: ​"^8.0.4"​,
 "babel-plugin-styled-components"​: ​"^1.9.2"​,
 "enzyme"​: ​"^3.7.0"​,
 "enzyme-adapter-react-16"​: ​"^1.7.0"​,
 "enzyme-to-json"​: ​"^3.3.5"​,
 "eslint"​: ​"^5.1.0"​,
 "eslint-plugin-jest"​: ​"^21.17.0"​,
 "eslint-plugin-react"​: ​"^7.10.0"​,
 "html-webpack-plugin"​: ​"^3.2.0"​,
 "husky"​: ​"^1.3.1"​,
 "jest"​: ​"^23.6.0"​,
 "jest-styled-components"​: ​"^6.3.1"​,
 "prettier-eslint-cli"​: ​"^4.7.1"​,
 "stylelint"​: ​"^9.9.0"​,
 "stylelint-config-recommended"​: ​"^2.1.0"​,
 "stylelint-config-styled-components"​: ​"^0.1.1"​,
 "stylelint-processor-styled-components"​: ​"^1.5.1"​,
 "webpack"​: ​"^4.26.1"​,
 "webpack-cli"​: ​"^3.1.2"​,
 "webpack-dev-server"​: ​"^3.1.10"
  },
 "dependencies"​: {
 "prop-types"​: ​"^15.7.2"​,
 "react"​: ​"^16.4.2"​,
 "react-dom"​: ​"^16.4.2"​,
 "styled-components"​: ​"^4.1.1"
  }
 }

Like the dist directory, the docs directory is going to include some generated code that doesn’t abide by our formatting standards, so add it to the project’s .eslintignore and .prettierignore:

 dist/
»docs/
 dist/
»docs/

Now run the script:

 $ ​​npm​​ ​​run​​ ​​build-storybook

This will generate a static web version of the project’s storybook in the docs directory we specified. (The particular choice of directory is important, for reasons that will become clear momentarily.) Once the script completes, create a commit with the new directory:

 :memo: Build storybook docs

Then push that commit:

 $ git push origin master

Now let’s ask GitHub to host our new docs for us. Open the project’s GitHub page and go to Settings. Scroll down to the “GitHub Pages” section. For the source, choose “master branch /docs folder,” then click Save as shown in the screenshot.

images/GitHub_Pages_settings.png

It may take a minute or two for GitHub to publish your page. You’ll see a link from the project’s Settings page to it. The address should be something like yourname.github.io/test-driven-carousel. Once it goes live, it should look exactly like your local Storybook page. Now every time you push changes to the docs directory on master, GitHub will update the project’s documentation site.

As it is, this setup has one problem: if you make changes to the project but forget to run the build-storybook script, the docs will become stale. There are a couple of possible solutions to this. One possibility is to add a Husky hook to package.json, e.g.:

 "husky"​: {
 "hooks"​: {
 "pre-push"​: ​"npm run build-storybook"
  }
 },

That would be a bit of a nuisance for developers, who would have to wait on the build every time they commit a change. An ideal solution would be for Travis to take care of it. That requires a few extra steps. First, you’ll want to go into the GitHub repo’s settings and switch to using the gh-pages as the source of the docs; that will avoid the possibility of an infinite loop where Travis sees changes to master, rebuilds the docs, pushes the new docs to master, sees changes to master, etc. From there, follow Travis CI’s guide to GitHub Pages deployment.[82]

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.235.79