gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.27k stars 10.31k forks source link

Storybook v5, TypeScript and SVG loader #12561

Closed elie222 closed 5 years ago

elie222 commented 5 years ago

Description

I have been struggling to get Storybook v5, Gatsby working with SVG loader and TS to work nicely together.

Steps to reproduce

Install the gatsby-plugin-svgr plugin. Import an SVG into a .tsx file. Gatsby should load this fine. Run Storybook.

Expected result

Storybook should run and import the SVG.

Actual result

Storybook does not load. The error is:

[tsl] ERROR in ...../src/components/Header/Header.tsx(3,30)
      TS2307: Cannot find module './header-background.svg'.
Child HtmlWebpackCompiler:
                          Asset     Size               Chunks  Chunk Names
    __child-HtmlWebpackPlugin_0  559 KiB  HtmlWebpackPlugin_0  HtmlWebpackPlugin_0
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
    [./node_modules/@storybook/core/node_modules/html-webpack-plugin/lib/loader.js!./node_modules/@storybook/core/dist/server/templates/index.ejs] 1.69 KiB {HtmlWebpackPlugin_0} [built]
    [./node_modules/@storybook/core/node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {HtmlWebpackPlugin_0} [built]
    [./node_modules/@storybook/core/node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {HtmlWebpackPlugin_0} [built]
    [./node_modules/lodash/lodash.js] 527 KiB {HtmlWebpackPlugin_0} [built]

Environment

  System:
    OS: macOS 10.14.3
    CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 10.1.0 - ~/.nvm/versions/node/v10.1.0/bin/node
    Yarn: 1.13.0 - ~/.nvm/versions/node/v10.1.0/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v10.1.0/bin/npm
  Languages:
    Python: 2.7.10 - /usr/local/bin/python
  Browsers:
    Chrome: 72.0.3626.121
    Firefox: 64.0.2
    Safari: 12.0.3
  npmPackages:
    gatsby: ^2.1.30 => 2.1.30 
    gatsby-link: ^2.0.15 => 2.0.15 
    gatsby-plugin-emotion: ^4.0.6 => 4.0.6 
    gatsby-plugin-glamor: ^2.0.9 => 2.0.9 
    gatsby-plugin-google-analytics: ^2.0.17 => 2.0.17 
    gatsby-plugin-manifest: 2.0.23 => 2.0.23 
    gatsby-plugin-offline: ^2.0.25 => 2.0.25 
    gatsby-plugin-sharp: ^2.0.27 => 2.0.27 
    gatsby-plugin-svgr: ^2.0.1 => 2.0.1 
    gatsby-plugin-typescript: ^2.0.0-rc.4 => 2.0.11 
    gatsby-remark-autolink-headers: ^2.0.16 => 2.0.16 
    gatsby-remark-copy-linked-files: ^2.0.10 => 2.0.10 
    gatsby-remark-images: ^3.0.9 => 3.0.9 
    gatsby-remark-prismjs: ^3.2.5 => 3.2.5 
    gatsby-source-filesystem: ^2.0.24 => 2.0.24 
    gatsby-transformer-json: ^2.1.10 => 2.1.10 
    gatsby-transformer-remark: ^2.3.2 => 2.3.2 
    gatsby-transformer-sharp: ^2.1.16 => 2.1.16 
  npmGlobalPackages:
    gatsby-cli: 2.4.15
elie222 commented 5 years ago

I have tried to update the Storybook webpack.config.js file in lots of different ways, but have not had any luck getting it working.

I have tried both the Storybook v4 and v5 notes in the Gatsby readme.

Attempt with Gatsby Storybook v5 instructions:

const path = require("path");

module.exports = ({ config }) => {
  // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]

  // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
  config.module.rules[0].use[0].loader = require.resolve("babel-loader")

  // use @babel/preset-react for JSX and env (instead of staged presets)
  config.module.rules[0].use[0].options.presets = [
    require.resolve("@babel/preset-react"),
    require.resolve("@babel/preset-env"),
  ]

  // use @babel/plugin-proposal-class-properties for class arrow functions
  config.module.rules[0].use[0].options.plugins = [
    require.resolve("@babel/plugin-proposal-class-properties"),
  ]

  // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
  config.resolve.mainFields = ["browser", "module", "main"]

  // Add typescript loader
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    include: path.resolve(__dirname, "../src"),
    loader: require.resolve("ts-loader"),
    options: {
      configFile: ".storybook/tsconfig.json"
    }
  });
  config.resolve.extensions.push(".ts", ".tsx");

  // Add markdown loader
  config.module.rules.push({
    test: /\.md$/,
    include: path.resolve(__dirname, "../src"),
    loader: require.resolve("raw-loader")
  });
  config.resolve.extensions.push(".md");

  // Add svg loader

  // modify storybook's file-loader rule to avoid conflicts with svgr
  const fileLoaderRule = config.module.rules.find(rule => rule.test.test('.svg'));
  fileLoaderRule.exclude = path.resolve(__dirname, "../src");

  config.module.rules.push({
    test: /\.svg$/,
    include: path.resolve(__dirname, "../src"),
    use: [{
      loader: '@svgr/webpack',
      options: {
        icon: true,
      },
    }],
  });

  return config
}
jonniebigodes commented 5 years ago

@elie222 i've picked up on your issue and based on the information you supplied i have circunvented that issue and i'm able to get build with storybook and gatsby. I'm going to break down my answer into smaller parts for better understanding:

// automatically import all files ending in *.stories.js const req = require.context('../src', true, /.stories.js$/); function loadStories() { req.keys().forEach(filename => req(filename)); } // Gatsby's Link overrides: // Gatsby defines a global called loader to prevent its method calls from creating console errors you override it here global.loader = { enqueue: () => {}, hovering: () => {}, } // Gatsby internal mocking to prevent unnecessary errors in storybook testing environment global.PATH_PREFIX_ = "" // This is to utilized to override the window.navigate method Gatsby defines and uses to report what path a Link would be taking us to if it wasn't inside a storybook window.___navigate = pathname => { action("NavigateTo:")(pathname) }

configure(loadStories, module);

- Created a `webpack.config.js` inside `.storybook` folder and added the Gatsby configuration used for v5  mentioned in [here](https://www.gatsbyjs.org/docs/visual-testing-with-storybook/) and as Gatsby uses babel under the hood and you're using typescript i added also the configuration mentioned here for [typescript](https://storybook.js.org/docs/configurations/typescript-config/#setting-up-typescript-with-babel-loader). 
Making the following the contents of the file:
```javascript
module.exports = ({ config }) => {
    // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
    config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]

    // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
    config.module.rules[0].use[0].loader = require.resolve("babel-loader")

    // use @babel/preset-react for JSX and env (instead of staged presets)
    config.module.rules[0].use[0].options.presets = [
      require.resolve("@babel/preset-react"),
      require.resolve("@babel/preset-env"),
    ]

    // use @babel/plugin-proposal-class-properties for class arrow functions
    config.module.rules[0].use[0].options.plugins = [
      require.resolve("@babel/plugin-proposal-class-properties"),
    ]

    // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
    config.resolve.mainFields = ["browser", "module", "main"]
    config.module.rules.push({
        test: /\.(ts|tsx)$/,
        loader: require.resolve('babel-loader'),
        options: {
          presets: [['react-app', { flow: false, typescript: true }]],
        },
      });

      config.resolve.extensions.push('.ts', '.tsx');
    return config
  }

const StarComponentContainer:React.FunctionComponent=()=>(

this is a star

); export default StarComponentContainer;

- Created a story for that component with the following code:
```javascript
import React from 'react';
import { storiesOf } from '@storybook/react';
import StarComponentContainer from './StarComponentContainer';

storiesOf('Star', module)
  .add('StarComponent default',()=><StarComponentContainer/>)

const TestPage:React.FunctionComponent=()=>(

This is a test page

); export default TestPage;

Storybook story code:
```javascript
import React from 'react';
import { storiesOf } from '@storybook/react';

import TestPage from './test';

storiesOf('Test Page',module)
.add('default',()=><TestPage/>)

There might be something here i'm not seeing and something else in terms of configuration might be needed. Sorry i could not be more of assistance.

elie222 commented 5 years ago

What an awesome response! Thanks for taking the time. Will take a look at this soon!

jonniebigodes commented 5 years ago

@elie222 no need to thank, glad i could be of some assistance. Sorry that i could not fix the issue entirely.

elie222 commented 5 years ago

Just read through it all now. Thanks for the help.

This is my attempt at getting things working:

https://github.com/elie222/elie-tech/tree/storybook

But no luck either. To see the issue at hand:

git clone git@github.com:elie222/elie-tech.git
cd elie-tech
git checkout storybook
yarn storybook
coreyward commented 5 years ago

@elie222 It doesn't look like you're declaring @svgr/webpack in your dependencies; is it being loaded by Storybook? Can you go ahead and add it and see if that resolves your issue? For what it's worth, gatsby-plugin-svgr 2.0.2 resolves an incorrect (overly narrow) peer dependency and could be related.

jonniebigodes commented 5 years ago

@coreyward @svgr/webpack is added to the project's dependencies, as you can see here. @elie222 i'm currently making some tests to see if i have figured out is actually the problem here. I'll post my findings as soon as i can. Sounds good?

elie222 commented 5 years ago

Sounds awesome ❤️ . This may be a problem with the latest version of Storybook. v5 just came out and there were a fair number of issues related to importing svgs/pngs on SB repo. I have posted there too:

https://github.com/storybooks/storybook/issues/6188

jonniebigodes commented 5 years ago

@elie222 looks like it worked. I'm going to break down the answer into smaller bits so that you can make adjustments as you go along. Going to start off with the typescript part and then move onto the storybook part.

// import favorite from "./favorite.svg"
import Favorite from "../../assets/icons/favorite.svg";

export default (props: ArticleItemProps) => {
  return (
    <Wrapper href={props.link} target="_blank">
       ......
      <Main>
        <Bottom>
          <Likes>
            {props.likes || 0}
            {/* <LikesIcon src={favorite} /> */}
            <Favorite/>
          </Likes>
          <Tags>{props.tags.map((tag) => `#${tag.toLowerCase()}`).join(", ")}</Tags>
        </Bottom>
      </Main>
    </Wrapper>
  )
}

ellie_build_ok

Sorry for the extremely long post, hope i could shed some insights and helpd solve your issue.

elie222 commented 5 years ago

Thanks so much for the help. Working through this now, but just fixing the TS import and reverting to SB 5.0.3 has got SB loading again at least!

Can I buy you a coffee (or 3), on something like: https://www.buymeacoffee.com/? Or send you a tip in Bitcoin/Eth?

elie222 commented 5 years ago

Also, I didn’t quite understand what you meant about me exposing items to graphql. I do load the data on the homepage using graphql so that I can use gatsby image. Is there another place I’m doing this for no need?

jonniebigodes commented 5 years ago

@elie222 i'm glad i could be of assistance. No need for the coffee but thanks for the offer. Also ok...i didn't go through the code with a fine tooth comb, just focused on the storybook part, so disregard the exposing items to graphl part of the comment.