Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add typescript docs #3361

Merged
merged 4 commits into from
Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = {
'/configurations/default-config/',
'/configurations/custom-webpack-config/',
'/configurations/custom-babel-config/',
'/configurations/typescript-config/',
'/configurations/add-custom-head-tags/',
'/configurations/serving-static-files/',
'/configurations/env-vars/',
Expand Down
3 changes: 3 additions & 0 deletions docs/src/components/Homepage/MainLinks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class MainLinks extends React.Component {
<li>
<Link to="/configurations/custom-webpack-config/">Webpack configurations</Link>
</li>
<li>
<Link to="/configurations/typescript-config/">Typescript configurations</Link>
</li>
<li>
<Link to="/configurations/add-custom-head-tags/">Custom scripts & styling</Link>
</li>
Expand Down
38 changes: 20 additions & 18 deletions docs/src/pages/configurations/custom-webpack-config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ Let's say you want to add [SASS](http://sass-lang.com/) support to Storybook. Th
Simply add the following content to a file called `webpack.config.js` in your Storybook config directory (`.storybook` by default ).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same with this Simply

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hahaha i didnt write that


```js
const path = require('path');
const path = require("path");

module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loaders: ["style-loader", "css-loader", "sass-loader"],
include: path.resolve(__dirname, '../')
include: path.resolve(__dirname, "../")
}
]
}
}
};
```

Since this config file stays in the Storybook directory, you need to set the include path as above. If the config directory stays in a different directory, you need to set the include path relative to that.
Expand All @@ -45,9 +45,9 @@ You also need to install the loaders (style, css, sass, as well as node-sass) us
You can add any kind of Webpack configuration options with the above config, whether they are plugins, loaders, or aliases.
But you won't be able to change the following config options:

- entry
- output
- js loader with babel
* entry
* output
* js loader with babel

For the advanced usage we strongly recommend [full control mode](#full-control-mode).

Expand All @@ -60,7 +60,7 @@ That's where you can use our full control mode.
To enable that, you need to export a **function** from the above `webpack.config.js` file, just like this:

```js
const path = require('path');
const path = require("path");

// Export a function. Accept the base config as the only param.
module.exports = (storybookBaseConfig, configType) => {
Expand All @@ -72,7 +72,7 @@ module.exports = (storybookBaseConfig, configType) => {
storybookBaseConfig.module.rules.push({
test: /\.scss$/,
loaders: ["style-loader", "css-loader", "sass-loader"],
include: path.resolve(__dirname, '../')
include: path.resolve(__dirname, "../")
});

// Return the altered config
Expand All @@ -82,10 +82,10 @@ module.exports = (storybookBaseConfig, configType) => {

Storybook uses the config returned from the above function. So, try to edit the `storybookBaseConfig` with care. Make sure to preserve the following config options:

- entry
- output
- first loader in the module.loaders (Babel loader for JS)
- all existing plugins
* entry
* output
* first loader in the module.loaders (Babel loader for JS)
* all existing plugins

> If your custom webpack config uses a loader that does not explicitly include specific file extensions via the `test` property, it is necessary to `exclude` the `.ejs` file extension from that loader.

Expand All @@ -96,28 +96,30 @@ If so, this is how you do it using the Full Control Mode.
Add following content to the `webpack.config.js` in your Storybook config directory.

```js
const path = require('path');
const path = require("path");

module.exports = (baseConfig, env, defaultConfig) => {
// Extend defaultConfig as you need.

// For example, add typescript loader:
defaultConfig.module.rules.push({
test: /\.(ts|tsx)$/,
include: path.resolve(__dirname, '../src'),
loader: require.resolve('ts-loader')
include: path.resolve(__dirname, "../src"),
loader: require.resolve("ts-loader")
});
defaultConfig.resolve.extensions.push('.ts', '.tsx');
defaultConfig.resolve.extensions.push(".ts", ".tsx");

return defaultConfig;
};
```

For full instructions on Typescript setup, check [our dedicated Typescript page](/configurations/typescript-config/).

## Using Your Existing Config

You may have an existing Webpack config for your project. So, you may need to copy and paste some config items into Storybook's custom Webpack config file.

But you don't need to. There are a few options:

- Simply import your main Webpack config into Storybook's `webpack.config.js` and use the loaders and plugins used in that.
- Create a new file with common Webpack options and use it in both inside the main Webpack config and inside Storybook's `webpack.config.js`.
* Simply import your main Webpack config into Storybook's `webpack.config.js` and use the loaders and plugins used in that.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this Simply?. If it's so simple, users wouldn't need to read the docs.

It should just say Import your main Webpack...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hahaha i didnt write that

* Create a new file with common Webpack options and use it in both inside the main Webpack config and inside Storybook's `webpack.config.js`.
229 changes: 229 additions & 0 deletions docs/src/pages/configurations/typescript-config/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
---
id: 'typescript-config'
title: 'Typescript Config'
---

This is a central reference for using Storybook with Typescript.

## Dependencies you may need

```bash
yarn add -D typescript
yarn add -D awesome-typescript-loader # alternative to ts-loader
Copy link
Member

@danielduan danielduan Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these two loaders interchangeable in this guide? we should leave a note about it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

yarn add -D @storybook/addon-info react-docgen-typescript-webpack-plugin # optional but recommended
yarn add -D jest "@types/jest" ts-jest #testing
```

## Setting up Typescript to work with Storybook

We first have to use the [custom Webpack config in full control mode, extending default configs](https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode--default):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think relative URLs work here, so /configurations/custom...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


```js
// load the default config generator.
const genDefaultConfig = require("@storybook/react/dist/server/config/defaults/webpack.config.js");
const path = require("path");
const TSDocgenPlugin = require("react-docgen-typescript-webpack-plugin"); // optional

module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: [
path.resolve(__dirname, "../src"),
path.resolve(__dirname, "../stories") // e.g. if you have a separate /stories folder
],
loader: require.resolve("awesome-typescript-loader") // or ts-loader
// alternatively
// loader: 'babel-loader!ts-loader',
});
config.plugins.push(new TSDocgenPlugin()); // optional
config.resolve.extensions.push(".ts", ".tsx");
return config;
};
```

The above example shows a working config with the TSDocgen plugin also integrated; remove the optional sections if you don't plan on using them.

## `tsconfig.json`

```json
{
"compilerOptions": {
"outDir": "build/lib",
"module": "commonjs",
"target": "es5",
"lib": ["es5", "es6", "es7", "es2017", "dom"],
"sourceMap": true,
"allowJs": false,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"baseUrl": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build", "scripts"]
}
```

If you have your stories in a separate `/stories` folder you may wish to replace `rootDir` above with `"rootDirs": ["src", "stories"]`.

## Using Typescript with the TSDocgen addon

The very handy [Storybook Info addon](https://github.com/storybooks/storybook/tree/master/addons/info) autogenerates prop tables documentation for each component, however it doesn't work with Typescript types. The current solution is to use [react-docgen-typescript-loader](https://github.com/strothj/react-docgen-typescript-loader) to preprocess the Typescript files to give the Info addon what it needs. The webpack config above does this, and so for the rest of your stories you use it as per normal:

```js
import React from "react";
import { storiesOf } from "@storybook/react";
import { withInfo } from "@storybook/addon-info";
import { action } from "@storybook/addon-actions";
import TicTacToeCell from "./TicTacToeCell";

const stories = storiesOf("Components", module);

stories.add(
"TicTacToeCell",
withInfo({ inline: true })(() => <TicTacToeCell value="X" position={{ x: 0, y: 0 }} onClick={action("onClick")} />)
);
```

## Customizing Type annotations/descriptions

Please refer to the [react-docgen-typescript-loader](https://github.com/strothj/react-docgen-typescript-loader) docs for writing prop descriptions and other annotations to your Typescript interfaces.

Additional annotation can be achieved by creating a `wInfo` higher order component:

```js
import { withInfo } from "@storybook/addon-info";
const wInfoStyle = {
header: {
h1: {
marginRight: "20px",
fontSize: "25px",
display: "inline"
},
body: {
paddingTop: 0,
paddingBottom: 0
},
h2: {
display: "inline",
color: "#999"
}
},
infoBody: {
backgroundColor: "#eee",
padding: "0px 5px",
lineHeight: "2"
}
};
export const wInfo = text => withInfo({ inline: true, source: false, styles: wInfoStyle, text: text });
```

This can be used like so:

```js
import React from "react";

import { storiesOf } from "@storybook/react";
import { PrimaryButton } from "./Button";
import { wInfo } from "../../utils";
import { text, select, boolean } from "@storybook/addon-knobs/react";

storiesOf("Components/Button", module).addWithJSX(
"basic PrimaryButton",
wInfo(`

### Notes

light button seen on <https://zpl.io/aM49ZBd>

### Usage
~~~js
<PrimaryButton
label={text('label', 'Enroll')}
disabled={boolean('disabled',false)}
onClick={() => alert('hello there')}
/>
~~~

`)(() => (
<PrimaryButton
label={text("label", "Enroll")}
disabled={boolean("disabled", false)}
onClick={() => alert("hello there")}
/>
))
);
```

And this is how it looks:

![image](https://user-images.githubusercontent.com/35976578/38376038-ac02b432-38c5-11e8-9aed-f4fa2e258f60.png)

Note: Component docgen information can not be generated for components that are only exported as default. You can work around the issue by exporting the component using a named export.

## Setting up Jest tests

The ts-jest [README](https://github.com/kulshekhar/ts-jest) explains pretty clearly how to get Jest to recognize TypeScript code.

This is an example package.json config for jest:

```json
"jest": {
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"mapCoverage": true,
"testPathIgnorePatterns": [
"/node_modules/",
"/lib/"
],
"testRegex": "(/test/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"json"
]
}
```

## Building your Typescript Storybook

You will need to set up some scripts - these may help:

```json
"scripts": {
"start": "react-scripts-ts start",
"build": "npm run lint && npm run build-lib && build-storybook",
"build-lib-watch": "tsc -w",
"build-lib": "tsc && npm run copy-css-to-lib && npm run copy-svg-to-lib && npm run copy-png-to-lib && npm run copy-woff2-to-lib",
"test": "react-scripts-ts test --env=jsdom",
"test:coverage": "npm test -- --coverage",
"eject": "react-scripts-ts eject",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"copy-css-to-lib": "cpx \"./src/**/*.css\" ./build/lib",
"copy-woff2-to-lib": "cpx \"./src/**/*.woff2\" ./build/lib",
"copy-svg-to-lib": "cpx \"./src/**/*.svg\" ./build/lib",
"copy-png-to-lib": "cpx \"./src/**/*.png\" ./build/lib",
"lint": "tslint -c tslint.json 'src/**/*.{ts,tsx}'"
},
```

## Related Issues and Helpful Resources

* [Issue: Add proper typescript webpack setup in readme #1778](https://github.com/storybooks/storybook/issues/1778)
Copy link
Member

@danielduan danielduan Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave these GitHub issues out of the docs. It's a lot of stuff to read through to get very little information. If you think there are useful information there, please copy and paste them to the doc instead.

* [Issue: Addons info and Typescript props docgen? #1519](https://github.com/storybooks/storybook/issues/1519)
* [Storybook, React, TypeScript and Jest](https://medium.com/@mtiller/storybook-react-typescript-and-jest-c9059ea06fa7)
* [React, Storybook & TypeScript](http://www.joshschreuder.me/react-storybooks-with-typescript/)