Skip to content
This repository has been archived by the owner on Nov 20, 2020. It is now read-only.

Use with TypeScript compiled with Babel 7 #23

Open
ssylvia opened this issue Aug 30, 2018 · 11 comments
Open

Use with TypeScript compiled with Babel 7 #23

ssylvia opened this issue Aug 30, 2018 · 11 comments

Comments

@ssylvia
Copy link

ssylvia commented Aug 30, 2018

I'm using Storybook 4 alpha and Babel 7 to compile typescript. Also using v3.0.0-rc0 of this lib. Here's my custom webpack config for Storybook:

module.exports = (baseConfig, env, defaultConfig) => {
  // Add Typescript Files
  defaultConfig.resolve.extensions.push(".ts", ".tsx");

  // Find Babel Loader
  const babelRules = defaultConfig.module.rules.filter(rule => {
    let isBabelLoader = false;

    if (rule.loader && rule.loader.includes("babel-loader")) {
      isBabelLoader = true;
    }

    if (rule.use) {
      rule.use.forEach(use => {
        if (typeof use === "string" && use.includes("babel-loader")) {
          isBabelLoader = true;
        } else if (
          typeof use === "object" &&
          use.loader &&
          use.loader.includes("babel-loader")
        ) {
          isBabelLoader = true;
        }
      });
    }

    return isBabelLoader;
  });
  // Add Typescript to Babel Loader Test
  // Add react-docgen-typescript-loader to rule
  babelRules.forEach(rule => {
    rule.test = /\.(jsx|tsx)$/;
    rule.use.push({
      loader: require.resolve("react-docgen-typescript-loader")
    });
  });

  return defaultConfig;
};

Still get no Props defined
screen shot 2018-08-30 at 6 12 27 pm

And my component

import React, { Component } from "react";
import { resolve } from "styled-jsx/css";
interface Props {
  /** The type of button */
  type: "primary" | "default";

  /** The click action */
  onClick?: () => void;
}

export class Button extends Component<Props> {
  buttonStyle = resolve`
    .button.primary {
        background-color: lightgreen;
    }
    .button.default {
        background-color: #fff;
        border: 1px solid lightblue;
    }
  `;

  render() {
    return (
      <button
        className={`button ${this.props.type} ${this.buttonStyle.className}`}
        type="button"
        onClick={this.props.onClick}
      >
        {this.props.children}
        {this.buttonStyle.styles}
        <style jsx>{`
          .button {
            border-radius: 0.5em;
            border: 0;
            cursor: pointer;
            padding: 1em;
          }
        `}</style>
      </button>
    );
  }
}

export default Button;
@ndelangen
Copy link

Try to log the defaultConfig before returning it, and look if there's smething different from what'd you'd expect?

@ssylvia
Copy link
Author

ssylvia commented Aug 31, 2018

@ndelangen Yep, if I log the the defaultConifg.module.rules right before returning the config, I get this:

[
  {
    "test": {},
    "use": [
      {
        "loader": "babel-loader",
        "options": {
          "cacheDirectory": "/Users/step6692/development/tests/storybook-ts/node_modules/.cache/react-storybook",
          "presets": [
            "@babel/env",
            "@babel/typescript",
            "@babel/react"
          ],
          "plugins": [
            "@babel/proposal-class-properties",
            "@babel/proposal-object-rest-spread",
            "styled-jsx/babel",
            [
              "/Users/step6692/development/tests/storybook-ts/node_modules/babel-plugin-react-docgen/lib/index.js",
              {
                "DOC_GEN_COLLECTION_NAME": "STORYBOOK_REACT_CLASSES"
              }
            ]
          ],
          "babelrc": false
        }
      },
      {
        "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/react-docgen-typescript-loader/dist/index.js"
      }
    ],
    "include": [
      "/Users/step6692/development/tests/storybook-ts"
    ],
    "exclude": [
      "/Users/step6692/development/tests/storybook-ts/node_modules"
    ]
  },
  {
    "test": {},
    "use": [
      {
        **"loader": "/Users/step6692/development/tests/storybook-ts/node_modules/raw-loader/index.js"
      }
    ]
  },
  {
    "test": {},
    "use": [
      "/Users/step6692/development/tests/storybook-ts/node_modules/style-loader/index.js",
      {
        "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/css-loader/index.js",
        "options": {
          "importLoaders": 1
        }
      },
      {
        "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/postcss-loader/lib/index.js",
        "options": {
          "ident": "postcss",
          "postcss": {}
        }
      }
    ]
  },
  {
    "test": {},
    "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/file-loader/dist/cjs.js",
    "query": {
      "name": "static/media/[name].[hash:8].[ext]"
    }
  },
  {
    "test": {},
    "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/svg-url-loader/index.js"
  },
  {
    "test": {},
    "loader": "/Users/step6692/development/tests/storybook-ts/node_modules/url-loader/dist/cjs.js",
    "query": {
      "limit": 10000,
      "name": "static/media/[name].[hash:8].[ext]"
    }
  }

@ssylvia
Copy link
Author

ssylvia commented Aug 31, 2018

FYI, here's my sample repo if it helps: https://github.com/ssylvia/storybook-4-docgen-sample.

@ndelangen
Copy link

Should "test": {}, be a string?

@ssylvia
Copy link
Author

ssylvia commented Aug 31, 2018

No, it's a regex: /\.(jsx|tsx)$/ so when I console.log it with stringify, it was shown as {}.

@strothj
Copy link
Owner

strothj commented Sep 1, 2018

Right now, the TypeScript docgen loader does its parsing, then passes the resulting code to the next loader. The next loader in this case is Babel, which currently is configured to run its own docgen plugin.

These are the configured Babel plugins in your example:

[ '@babel/proposal-class-properties',
  '@babel/proposal-object-rest-spread',
  'styled-jsx/babel',
  [ 'C:\\Users\\jason\\code\\public\\storybook-4-docgen-sample\\node_modules\\babel-plugin-react-docgen\\lib\\index.js',
    { DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES' } ] ]

Each parsed component has code appended to the bottom of the file which adds an entry to the global STORYBOOK_REACT_CLASSES. Adding the following allows us to get a dump of the currently parsed docgen information:

index.stories.tsx:

/* tslint:disable-next-line:no-console */
// @ts-ignore
console.log("window.STORYBOOK_REACT_CLASSES", window.STORYBOOK_REACT_CLASSES);

Here we can see that there are two sets of results for the same component file. One of them is empty because the Babel version generates the docgen from React propTypes.

image

I added this ugly filter line in your Webpack config and got it to work. It just takes off the last Babel plugin, which in this case is the docgen plugin.

webpack.config.js:

babelRules[0].use[0].options.plugins = babelRules[0].use[0].options.plugins.slice(0, 3);
[ '@babel/proposal-class-properties',
  '@babel/proposal-object-rest-spread',
  'styled-jsx/babel' ]

image

image

I think this might be a better test line for your Babel loader: rule.test = /\.[jt]sx?$/;

I'm glab you brought this up. I wasn't aware that this could happen. I'll need to investigate if there's something I can do on my end to detect this or maybe work out an easier solution.

@ssylvia
Copy link
Author

ssylvia commented Sep 1, 2018

Thanks @strothj, that solved my issue. Feel free to close the issue unless you want to keep it open to track "detecting multiple docgen instances."

@strothj
Copy link
Owner

strothj commented Sep 1, 2018

Yep, I'm going to keep this open for now.

@lostfictions
Copy link

lostfictions commented Oct 16, 2018

Got bit by this as well -- but I've followed @strothj's solution, stepped through my configs, and still can't seem to get the Storybook Info addon to recognize my props. It seems like there's a lot of potential points of failure here and I'm finding it extremely difficult to debug this -- it might've been something that changed in Storybook between the alpha and the current rc, but I'm not sure.

Any chance of adding info for usage with Babel to the docs?

EDIT: whoops, nevermind -- I just missed the comment about using React.Component vs Component. It works!

@mattdell
Copy link

I'm having the same problem. Using Babel 7 with TypeScript. Can't seem to fix it with the ugly babelRules hack in the above. 😕

@milesj
Copy link

milesj commented Apr 15, 2019

Having the same issue. I filtered out babel-plugin-react-docgen and added react-docgen-typescript-loader after babel-loader, but I'm unable to get any prop types extracted. Digging into it a bit more.

Edit 1: I've been placing console.logs all over this loaders source code. I logged componentDocs (https://github.com/strothj/react-docgen-typescript-loader/blob/master/src/loader.ts#L113) and it's always empty. I'm using tsconfigPath + project references, which it might not handle?

Edit 2: If I remove tsconfigPath, it does find components, but the props is always an empty object...
Screen Shot 2019-04-15 at 11 14 56 AM

Edit 3: If I use compilerOptions directly, it does find components and props, but the description is now empty... lol. This is better than nothing!
Screen Shot 2019-04-15 at 11 34 00 AM

So to recap:

DOES NOT WORK:

babelConfig.use.push({
  loader: 'react-docgen-typescript-loader',
});
// OR
babelConfig.use.push({
  loader: 'react-docgen-typescript-loader',
  options: { tsconfigPath: path.join(__dirname, '../tsconfig.json') },
});

WORKS ENOUGH:

const tsConfig = require('../tsconfig.options.json');

babelConfig.use.push({
  loader: 'react-docgen-typescript-loader',
  options: { compilerOptions: tsConfig.compilerOptions },
});

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants