-
Notifications
You must be signed in to change notification settings - Fork 46
No propTypes defined! when using create-react-app and babel-loader 8.0.4 #33
Comments
Unfortunately the Storybook docs are out of date. Try this const path = require('path')
/**
*
* @param baseConfig
* @param env
* @param {webpack.Configuration} config
* @return {webpack.Configuration}
*/
module.exports = (baseConfig, env, config) => {
// TypeScript support
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: require.resolve('ts-loader'),
options: {
transpileOnly: true,
},
},
require.resolve('react-docgen-typescript-loader'),
],
})
config.resolve.extensions.push('.ts', '.tsx')
return config
} {
"compilerOptions": {
"outDir": "build",
"module": "esnext",
"target": "es5",
"lib": [
"es6",
"esnext",
"dom"
],
"jsx": "react",
"moduleResolution": "node",
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"allowJs": true
},
"include": [
"src/**/*",
".storybook/*"
]
} |
So... is the second code block meant to be added to the file tsconfig.json in the app folder? In .storybook, there is another tsconfig.json. Should I change it, as well? If I don't do it, I get the following error message now:
|
I was able to get this to work using CRA and babel-loader. Here is my complete config: // .storybook/webpack.config.js
const path = require('path');
module.exports = (_baseConfig, _env, config) => {
config.node = {
fs: 'empty',
net: 'empty',
tls: 'empty',
};
config.module.rules.push({
test: /\.tsx?$/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve('babel-preset-react-app')],
},
},
require.resolve('react-docgen-typescript-loader'),
],
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}; // .storybook/config.js
import { configure, addDecorator } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
function loadStories() {
addDecorator(withInfo);
require('../src/stories/index.stories.tsx');
}
configure(loadStories, module); // src/stories/index.stories.tsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
...
storiesOf('My Component', module)
.add('foo', () => {
return <MyComponent names={['Bill', 'Sandra']} status="online" />;
}, { info: { inline: true } }); |
This works for me, thank you! It would be good to have this in the official documentation. |
Also I've been notified that the term "SFC"(Stateless Functional Components) is being deprecated since Hooks can add state to functional components. Edit 3: Further test showed that it was me using React.SFC/React.FunctionComponent instead of SFC or FunctionComponent that caused it as stated in the react-docgen-typescript readme. For some reason I previously assumed this was only an issue when using classes. |
Does anyone have a fully working, minimal example repo of this that they can share? Perhaps we could link to it in the docs. |
Thank you @stevehanson for your solution! @teddybradford I created a full sample repo that others can use, could be linked to in the documentation I guess :) |
@stevehanson (or anyone else), what is the reason you need to add
to make this work? I tried removing it and it stopped working (wanting something as close to the official docs as possible). Just want to understand fully 😄 |
That has to do with the way dependencies are resolved. Whether or not passing a naked If you pass |
Do you mind if I pull this into the examples in the repo? |
Sure go ahead! |
I've tried @stevehanson's solution above but no luck. Am I missing something? My configuration seems the same as above, but I keep getting "No propTypes defined!" // .storybook/webpack.config.js
module.exports = ({ config }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve('babel-preset-react-app')],
},
},
require.resolve('react-docgen-typescript-loader'),
],
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}; // .storybook/config.js
import { addDecorator, configure } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';
import { withInfo } from '@storybook/addon-info';
addDecorator(withKnobs);
addDecorator(withInfo);
const req = require.context('../', true, /\.stories\.tsx$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module); // components/Button/Button.stories.tsx
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { text } from '@storybook/addon-knobs';
import Button from './Button';
storiesOf('Button', module)
.add('default', () => <Button>{text('Text', 'Hello World')}</Button>, {
info: { inline: true },
}); // components/Button/Button.tsx
import React from 'react';
import cx from 'classnames';
const styles = require('./Button.module.scss');
interface Props {
type?: 'button' | 'submit' | 'reset';
clearDefaultButtonStyle?: boolean;
}
/* eslint-disable react/button-has-type */
const Button: React.StatelessComponent<Props> = ({
children,
clearDefaultButtonStyle,
type = 'button',
}) => (
<span
className={cx({
[styles.clearDefaultButtonStyles]: clearDefaultButtonStyle,
})}
>
<button type={type}>{children}</button>
</span>
);
export default Button; |
We have an almost identical setup as @mattdell and have the same problem. All of our props show up as No Proptypes defined. We aren't using CRA however and so our webpack looks like this: const path = require('path');
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: path.resolve(__dirname, "../stories"),
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve('@babel/preset-react'), require.resolve('@babel/preset-typescript')],
}
},
require.resolve("react-docgen-typescript-loader"),
]
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}; Also worth mentioning is that we are using a monorepo and importing our components from another package into our storybook application. |
We are also using a monorepo, not sure if that is the issue, but i noticed that when I use addDecorator directly after
Here is my index.stories.tsx: import React from "react";
import { AudioPlayer } from "./";
import { storiesOf } from "@storybook/react";
import { withInfo } from "@storybook/addon-info";
const clip = "http://dare.wisc.edu/sites/dare.wisc.edu/files/HI009clip.mp3";
storiesOf("AudioPlayer", module)
.addDecorator(withInfo)
.add("hawaii clip", () => <AudioPlayer src={clip} />, {
info: { inline: true }
})
.add("with duration", () => <AudioPlayer src={clip} />, {
info: { inline: true }
}); |
Ok I found the solution for us. If you are writing your stories using typescript, you need to make sure the the Here is what our babel-loader is: {
module: {
rules: [
{
test: /\.tsx?$/,
// make sure not to compile story files!
exclude: [/node_modules/, /\.stories\.tsx$/, /__tests__/],
use: [
{
loader: "babel-loader",
options: {
configFile: require.resolve("@franchises/common/babel-config"),
plugins: [!opts.cold && "react-hot-loader/babel"].filter(
Boolean
)
}
},
opts.docgen && require.resolve("react-docgen-typescript-loader")
].filter(Boolean)
},
// If you want to use typescript for your stores, add this section
{
test: /\.stories\.tsx?$/,
exclude: [/node_modules/, /__tests__/],
use: [
{
loader: "babel-loader",
options: {
configFile: require.resolve("@franchises/common/babel-config")
}
}
]
}
]
}
} |
No difference. 😕 |
This is working for me: webpack.config.js
ColorButton.tsx
stories/index.js
|
I was having this issue and realized the culprit was the way I was importing the component to my story. My directory: My component in import React from "react";
interface IProps {
/**
* Text for the button
*/
text: string | JSX.Element;
/**
* Callback function for actions
*/
onClick?: () => undefined;
}
const Button = ({
text,
onClick
}: IProps) => {
const style = {
cursor: "pointer"
};
return (
<a
style={style}
onClick={onClick}
>
{text}
</a>
);
};
export default Button; Which I changed to this: import React from "react";
interface IProps {
/**
* Text for the button
*/
text: string | JSX.Element;
/**
* Callback function for actions
*/
onClick?: () => undefined;
}
export const Button = ({
text,
onClick
}: IProps) => {
const style = {
cursor: "pointer"
};
return (
<a
style={style}
onClick={onClick}
>
{text}
</a>
);
}; ... and I was exporting from import Button from "./Button/button";
export { Button }; Which I changed to this: import { Button } from "./Button/button";
export { Button }; Then finally, in my import { Button } from "../src"; ... resolved my issue |
Ok so I realized something very obvious that was dumb of us to miss. We are also importing our components but from a separate package in our monorepo. So of course the dockgen plugin wasn't doing anything in our stories package. There are no components there to compile! I added the docgen to our component library package so the output from there is compiled with the docgen plugin and all is well again. Nothing to do with how we were exporting our components. Although I'm pretty sure in the docs it explicitly states that all components need to have a named export. So to reiterate we have our webpack in our stories package: const path = require('path');
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: path.resolve(__dirname, "../stories"),
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve('@babel/preset-react'), require.resolve('@babel/preset-typescript')]
}
}
]
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}; and then we have our webpack in our component library package: const path = require('path');
module.exports = {
entry: { "index": path.resolve(__dirname, '../src/index.ts') },
mode: "development",
output: {
path: path.resolve(__dirname, '../lib'),
filename: '[name].js',
library: "@app/ui",
libraryTarget: 'umd'
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
externals: {
'react': 'react',
'react-dom': 'reactDOM',
"styled-components": "styled-components"
},
devtool: "source-map",
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: require.resolve('ts-loader')
},
require.resolve("react-docgen-typescript-loader"),
]
}
]
}
} An example of a component looks like this: import * as React from 'react';
import styled from 'styled-components';
export interface IButton extends IButtonStyle {
/**
* text
*/
text?: string;
/**
* Button action
*/
action: () => void
}
export interface IButtonStyle {
/**
* color
*/
color?: string;
/**
* background color
*/
bgColor?: string;
}
const StyledButton = styled.button<IButtonStyle>`
background-color : ${props => props.bgColor};
color: ${props => props.theme.palette.primary["500"]};
border-radius: 2px;
height: 2em;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
border-width: 1px;
border-color: ${props => props.color};
`;
export const Button: React.FunctionComponent<IButton> = ({ text = 'defaultText', ...props }: IButton) => {
return (
<StyledButton onClick={props.action} color={props.color} bgColor={props.bgColor}>{text}</StyledButton>
)
};
Button.displayName = "Button"; when we run webpack it compiles all of our d.ts files and components into alib/index.js and index.d.ts import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';
import { Button } from '@app/ui-components';
const action = () => { console.log('Hey!') };
const stories = storiesOf("Components", module);
stories.add('Button', () => (
<Button action={action} color="blue" text="hello world" bgColor="white" />
)); and everything works wonderfully :). |
For me work this method #33 (comment) with this webpack.config.js
|
I feel like I've tried everything in this thread. My code sample is above if anyone is able to have a look. I'm using |
@mattdell Do you have a repo that reproduces the issue that I could look at? |
My problem ended up being that instead of |
I've finally figured out my problem! I noticed that one of my components was working and through trial and error managed to figure out the cause. The component that works was defined as such...
The one that does not work was defined like this...
This is because the first component is defined without children and the second prop uses children. My understanding is that using Although this does allow it to work for this case, I don't want to have to implement Any thoughts on why this issue occurs? Tagging @draftitchris |
Is no one else using |
Sorry I totally forgot about this thread. We use React.FunctionComponent (now React.FC, but same thing) without any problems. You don't have to explicitly declare children unless you are using children btw. Ex: const CompNotUsingChildren : React.FC<{prop1:string}> = ({prop1}) => <div>{prop1}</div>;
const CompUsingChildren : React.FC<{prop1:string, children}> = ({prop1, children}) => <div><h1>{prop1}</h1>{children}</div>
or
interface Props{
prop1: string;
}
const CompUsingChildren : React.FC<Props> = (props) => <div><h1>{props.prop1}</h1>{props.children}</div> It shouldn't affect the way docgen emits to storybook as far as I can tell. Its really hard to guess without seeing it as a whole.... right now we've been refactoring a lot so our info in storybook is disabled but it will be fixed in the near future... hopefully I can provide some more insight then. As for now without some sort of repo to reproduce your problem its hard to say. |
@mattdell same thing for me, React.FunctionComponent/React.FC does not work for me.
|
Am working on a PR to reinstate this addon into our storybook now in our library and was able to get it working no problems with React.FunctionComponent/React.FC I am just looking over your earlier configuration and noticed two things.
I am assuming you've done this already though its impossible to tell without an update example or a link to a repo that I can look at. Another thing worth mentioning is that if you don't have your webpack.config in the root you might need to tell react-docgen-typescript-loader to find your tsconfig file. Ex: (if your webpack.config file is one level down from your root, aka ./webpack/webpack.config.js) {
loader: require.resolve("react-docgen-typescript-loader"),
options: {
tsconfigPath: path.join(__dirname, "../tsconfig.json"),
},
}, You could also test removing ALL withInfo decorators from ALL of your stories and adding it in the root of your storybook config. so that your config might look like this: import { configure, addDecorator, addParameters} from "@storybook/react";
import { withKnobs } from "@storybook/addon-knobs";
import { withInfo} from "@storybook/addon-info";
function loadStories() {
const req = require.context("../stories", true, /\.stories\.tsx$/);
req.keys().forEach(filename => req(filename));
}
addDecorator(
withInfo({
inline: true,
})
);
addParameters({
backgrounds: [
{ name: "white", value: "#ffffff" },
{ name: "light", value: "#f2f2f2", default: true },
{ name: "dark", value: "#a1a1a1" },
],
});
addDecorator(withKnobs);
configure(loadStories, module); This should add withInfo to all of your stories with inline true. AddParameters are for a seperate react-addon that can change the background color so those aren't relevant. Finally make sure you are using the latest react and addon-info version. |
Specifying the path to the tsconfig file fixed things for me, thanks! To wit, my directory structure looks like this:
The project is using Next.js and doesn't explicitly define its own webpack config, so as recommended by the Storybook docs we just put one in the |
It worked for me too, thanks ! |
It worked for me as well, great thanks! |
So is there any reason this loader doesnt work when you're only exporting the component as default? |
I've spent a lot of time looking for a solution why I like clean solutions so my components looks like this: export default function MyComponent(props: MyComponentProps) {
return <></>;
} To make function MyComponent(props: MyComponentProps) {
return <></>;
}
export default MyComponent; @strothj can you support my first example? |
I created a test project with create-react-app, added Typescript and Storybook by following the recommendations in the following storybook issue:
storybookjs/storybook#4739
Then I added the docgen generator as described here:
https://storybook.js.org/configurations/typescript-config/
This left me with following files.
webpack.config.js:
package.json:
The result looks like this:
I guess this issue might be related to #23. Any idea how to solve it?
The text was updated successfully, but these errors were encountered: