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

preset-create-react-app all files need to be in a src/ #9514

Closed
Nber1 opened this issue Jan 17, 2020 · 35 comments
Closed

preset-create-react-app all files need to be in a src/ #9514

Nber1 opened this issue Jan 17, 2020 · 35 comments

Comments

@Nber1
Copy link

Nber1 commented Jan 17, 2020

You are forced to include all files in a /src file

What the hell happened here?

    (plugin: { appSrcs: string[] }) => {
      if (plugin.appSrcs) {
        // Mutate the plugin directly as opposed to recreating it.
        // eslint-disable-next-line no-param-reassign
        plugin.appSrcs = [...plugin.appSrcs, resolve(options.configDir)];
      }
      return plugin;
    },
  );

That's clearly a breaking change and as it looks has nothing to do with the bug which the commit links to.

@shilman shilman added cra Prioritize create-react-app compatibility question / support labels Jan 17, 2020
@shilman
Copy link
Member

shilman commented Jan 17, 2020

@Nber1 can you elaborate on what you'd like to see changed? Happy to bump the version to 2.0.0.

@Nber1
Copy link
Author

Nber1 commented Jan 27, 2020

Please revert 1.5.2 and publish the part above as 2.0.0 so it is clear where the breaking change happened.

@shilman
Copy link
Member

shilman commented Jan 27, 2020

cc @mrmckeb

@mrmckeb
Copy link
Member

mrmckeb commented Jan 27, 2020

@Nber1, first I understand you're frustrated - but (unless I'm mistaken) this is not a breaking change for users that use Create React App using defaults.

However, we do our best to support the various ways people use CRA, and we certainly would have released this as breaking if we expected it to break any known uses.

Can you please provide more information? What files do you have outside of src? An example repo would be great - and would help us know where we need to add tests for future.

In the meantime, please use the previous version and @shilman and I will look to update this soon as you can provide additional information.

@Nber1
Copy link
Author

Nber1 commented Jan 27, 2020

The company I work for never used a src file structure, instead it is using an index.tsx and internal folder. Imported files to storybook/story come from the index.tsx.

@mrmckeb
Copy link
Member

mrmckeb commented Jan 27, 2020

@Nber1 it's not possible to use a different folder (other than src with CRA) - are you using a framework like react-app-rewired, craco, etc?

Or do you mean that your stories live outside of src?

@Nber1
Copy link
Author

Nber1 commented Jan 27, 2020

IMO, it should be marked as a breaking change by defintion, because you are changing something optional to be required, even if it won't affect anybody it should be marked as one.

@mrmckeb
Copy link
Member

mrmckeb commented Jan 27, 2020

Thanks for the feedback - can you please show me which line you're referring to, @Nber1?

I saw that you wrote (but removed) the following too:

Oh, now I understand what needs to be in the src folder, I thought it would need all files included into a src folder and not just the stories.

Does that mean this is not an issue for you?

@Nber1
Copy link
Author

Nber1 commented Jan 27, 2020

No, the issue is, that I need to include all files in src, not only the storys, either I will get this error message:

Module not found: Error: You attempted to import ../index which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project's node_modules/.

EDIT: I am still talking about this lines added in the last commit:
https://github.com/storybookjs/presets/blob/2411dc9ecc8dbaf184159c0df5f9d9becec85562/packages/preset-create-react-app/src/index.ts#L94

@mrmckeb
Copy link
Member

mrmckeb commented Jan 27, 2020

@Nber1 can you please give us some information about your project set up - what files are outside of src? How do they work with CRA now?

A demo repository would be brilliant, but a written description would be enough.

Thanks!

@noelblaschke
Copy link

@Nber1 ,

As a quick fix: You could also fixate "@storybook/preset-create-react-app": "1.5.1" in your package.json - this is the version before the change.

Best regards

@mrmckeb
Copy link
Member

mrmckeb commented Mar 1, 2020

Hi @Nber1 and @noelblaschke, if either of you can provide a repro repo, I can take a look and try to find a solution for you. Just let me know!

@stale
Copy link

stale bot commented Mar 22, 2020

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

@stale stale bot added the inactive label Mar 22, 2020
@shazhko-artem2
Copy link

shazhko-artem2 commented Mar 22, 2020

We have the same problem. We use the "js" folder instead "src" and we have follow errors:
`
ERROR in ./js/stories/Button.tsx 3:7
Module parse failed: Unexpected token (3:7)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import React, { FC, ReactNode, Component } from "react";
|

export type ButtonProps = {
| children: ReactNode;
|
@ ./js/stories/Test.stories.mdx 19:0-34 43:7-13 48:6-12 72:16-22
@ ./js sync ^./(?:(?:|[\/]|(?:(?:(?!(?:|[\/]).).)?)[\/])(?!.)(?=.)[^\\/]?.stories.(ts|tsx|js|jsx|mdx))$
@ ./.storybook/generated-entry.js
@ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js ./node_modules/@storybook/addon-docs/dist/frameworks/react/config.js ./node_modules/@storybook/addon-knobs/dist/preset/addDecorator.js ./.storybook/generated-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=true`

It's work fine in "src" folder but not in other.

@ldeveber
Copy link

ldeveber commented Apr 8, 2020

I am also seeing this issue. I made an app today with create-react-app, and added storybook. I like to keep things separate, so I changed the directories to be as follows:

- project/
  - src/
  - stories/
  - test/

And changed the appropriate line in ./storybook/main.js to stories: ['../stories/**/*.stories.js'],. This broke everything! Once I reverted this change, everything just worked.

@lucaslz2020
Copy link

lucaslz2020 commented Apr 9, 2020

I am also seeing this issue when I use storybook-addon-intl to load internationalized resources

error

ERROR in ./.storybook/preview.js
Module not found: Error: 
You attempted to import ../packages/business/src/locale/zh_TW 
which falls outside of the project src/ directory. 
Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project's node_modules/.

project

.storybook
  main.js
  preview.js
packages
  common
  business

preview.js

import { addDecorator } from "@storybook/react";
import { setIntlConfig, withIntl } from "storybook-addon-intl";
import en_US from "../packages/business/src/locale/en_US";
import zh_CN from "../packages/business/src/locale/zh_CN";
import zh_TW from "../packages/business/src/locale/zh_TW";

const messages = {
 " en-US,":  en_US,
 "zh-CN": zh_CN,
 "zh-TW": zh_TW
};

const getMessage = locale => messages[locale];

setIntlConfig({
  locales: ["en-US", "zh-CN", "zh-TW"],
  defaultLocale: "en-US",
  getMessage,
});
addDecorator(withIntl);

version

  • "@storybook/addon-actions": "6.0.0-alpha.31"
  • "storybook-addon-intl ": "2.4.1"
  • "react-intl": "^4.1.1",
  • "intl": "^1.2.5",

@mrmckeb
Copy link
Member

mrmckeb commented Apr 17, 2020

@ldeveber I don't recommend that approach - I find it's generally better to keep stories and tests alongside components. It makes things easier contextually, and developers are more likely to keep tests/stories updated as they make changes.

As mentioned, Storybook is using CRAs Webpack config here... so folders outside of src won't be processed and you'll need to modify the Webpack config yourself.

@mrmckeb
Copy link
Member

mrmckeb commented Apr 17, 2020

@lucasleelz Again these need to be in src I believe. You could modify the Webpack config if you need support for folders outside of src and .storybook.

@lucaslz2020
Copy link

@mrmckeb but, 6.0.0 support for folders outside of src and .storybook.

@stale
Copy link

stale bot commented May 9, 2020

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

@stale stale bot added the inactive label May 9, 2020
@stale
Copy link

stale bot commented Jun 8, 2020

Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

@stale stale bot closed this as completed Jun 8, 2020
@baurine
Copy link

baurine commented Jul 14, 2020

My case (may not very common, it has a real project in https://github.com/pingcap-incubator/tidb-dashboard/tree/master/ui), the following is the project files structure:

- src
  - index.ts (import files from dashboardApp)
- dashboardApp
  - index.tsx (import files from lib)
  - ...
- lib
  - components
  - utils
  - ...

The project is initialized by CRA and typescript, then uses react-app-rewired and customized-cra to customize webpack config.

I init the storybook by npx -p @storybook/cli sb init --story-format=csf-ts according to https://gist.github.com/shilman/bc9cbedb2a7efb5ec6710337cbd20c0c , it works fine.

Then I add a new story in the src/stories/2-MetricChart.stories.tsx , the component imports the MetricChart from "../../lib/components", then I get the following error:

ERROR in ./src/stories/2-MetricChart.stories.tsx
Module not found: Error: You attempted to import ../../lib/components which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project's node_modules/.
 @ ./src/stories/2-MetricChart.stories.tsx 3:0-51 6:13-24 8:58-69
 @ ./src sync ^\.\/(?:(?:|\/|(?:(?:(?!(?:|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(ts|tsx|js|jsx))$
 @ ./.storybook/generated-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/generated-entry.js ./node_modules/webpack-hot-middleware/client.js?reload=true&quiet=true

Then I put the story in the same place as the responding component under the lib/components folder. It looks like the following:

- lib
   - components
     - MetricChart
       - index.tsx
       - index.stories.tsx

Also, change the .storybook/main.js to stories: ['../lib/**/*.stories.(ts|tsx|js|jsx)'].

The index.stories.tsx likes this:

import React from 'react'
import MetricChart from './'

export default {
  title: 'MetricChart',
  component: MetricChart,
}

export const QPS = () => (
  <MetricChart
    title="QPS"
    series={[
      {
        query: 'sum(rate(tidb_server_query_total[1m])) by (result)',
        name: 'Queries {result}',
      },
    ]}
    unit="ops"
    type="bar"
  />
)

Then I get the following error:

Module parse failed: Unexpected token (10:2)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
| export const QPS = () => (
>   <MetricChart
|     title="QPS"
|     series={[

@mrmckeb , please help have a look, thanks in advance!

@baurine
Copy link

baurine commented Jul 14, 2020

image

Upgrade to 6.0.0-rc.3, still has the same errors.

cc @shilman @mrmckeb

@baurine
Copy link

baurine commented Jul 14, 2020

According to the documents in https://storybook.js.org/docs/basics/writing-stories/#story-file-location , it says components and stories can put outside src, but why actually it can't?

image

(Or this diagram is not correct? It seems it looks different when you copy and paste it by text)

•
└── src
    └── components
        └── button
            ├── button.js
            └── button.stories.js

@baurine
Copy link

baurine commented Jul 14, 2020

@lucasleelz Again these need to be in src I believe. You could modify the Webpack config if you need support for folders outside of src and .storybook.

hi @mrmckeb , how can we do it for storybook, I mean modify webpack config.

@baurine
Copy link

baurine commented Jul 15, 2020

Resolve the compile errors by following main.js config:

const path = require('path')

function includeMorePaths(config) {
  // find rule to handle *.tsx files
  for (const rule of config.module.rules) {
    for (const subRule of rule.oneOf || []) {
      // /\.(js|mjs|jsx|ts|tsx)$/
      if (subRule.test instanceof RegExp && subRule.test.test('.tsx')) {
        libFolder = path.resolve(__dirname, '../lib')
        subRule.include.push(libFolder)
        break
      }
    }
  }

  return config
}

function addMoreAlias(config) {
  config.resolve.alias['@lib'] = path.resolve(__dirname, '../lib')
  return config
}

module.exports = {
  stories: ['../lib/components/**/*.stories.@(ts|tsx|js|jsx)'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-actions',
    '@storybook/addon-links',
  ],
  webpackFinal: (config) => addMoreAlias(includeMorePaths(config)),
}

Now it works fine after running yarn storybook:

> yarn storybook
yarn run v1.21.1
$ start-storybook -p 9009 -s public
info @storybook/react v6.0.0-rc.3
info
info => Loading static files from: ...
info => Loading presets
info => Loading presets
info => Loading config/preview file in "./.storybook".
info => Adding stories defined in ".storybook/main.js".
info => Loading Webpack configuration from `node_modules/react-scripts`
info => Removing existing JavaScript and TypeScript rules.
info => Modifying Create React App rules.
info => Using default Webpack setup.
webpack built 51ec00edaa81ec139a56 in 28494ms
╭──────────────────────────────────────────────────────╮
│                                                      │
│   Storybook 6.0.0-rc.3 started                       │
│   9.94 s for manager and 31 s for preview            │
│                                                      │
│    Local:            http://localhost:9009/          │
│    On your network:  http://192.168.188.120:9009/    │
│                                                      │
╰──────────────────────────────────────────────────────╯

But, there is still runtime error:

image

image

I have no idea why this error happens.

The full commit is here: pingcap/tidb-dashboard@d6b4d37

@baurine
Copy link

baurine commented Jul 15, 2020

downgrade to 5.3 still has the same error, finally, changing my code writing way fixes it:

// old way
MultiSelect.Plain = PlainMultiSelect

// new way
export { PlainMultiSelect }

Full commit is here: pingcap/tidb-dashboard@27499af

@baurine
Copy link

baurine commented Jul 16, 2020

A reference to handle files outside src folder if you use customize-cra:

It works for my project with following config:

const path = require('path')

function includeMorePaths(config) {
  // fine rule to handle *.tsx files
  for (const rule of config.module.rules) {
    for (const subRule of rule.oneOf || []) {
      // /\.(js|mjs|jsx|ts|tsx)$/
      if (subRule.test instanceof RegExp && subRule.test.test('.tsx')) {
        subRule.include.push(path.resolve(__dirname, '../lib'))
        break
      }
    }
  }

  return config
}

// ref: https://harrietryder.co.uk/blog/storybook-with-typscript-customize-cra/
const custom = require('../config-overrides')

module.exports = {
  stories: ['../lib/components/**/*.stories.@(ts|tsx|js|jsx)'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-actions',
    '@storybook/addon-links',
  ],
  webpackFinal: (storybookConfig) => {
    const customConfig = custom(storybookConfig)
    const newConfigs = {
      ...storybookConfig,
      module: { ...storybookConfig.module, rules: customConfig.module.rules },
    }
    return includeMorePaths(newConfigs)
  },
}

Full commit: pingcap/tidb-dashboard@4bac5a6

@baurine
Copy link

baurine commented Jul 16, 2020

According to the documents in https://storybook.js.org/docs/basics/writing-stories/#story-file-location , it says components and stories can put outside src, but why actually it can't?

image

(Or this diagram is not correct? It seems it looks different when you copy and paste it by text)

•
└── src
    └── components
        └── button
            ├── button.js
            └── button.stories.js

btw, @shilman @mrmckeb can you fix this on the document site page? it really misguided the reader. Create an issue for it: #11573

@mrmckeb
Copy link
Member

mrmckeb commented Jul 22, 2020

Create React App simply doesn't support files outside of src, and the CRA preset doesn't really deviate from that.

You can, if you wish, modify/override the preset (using webpackFinal) and allow for stories to be wherever you'd like them to be.

Personally, I always keep stories alongside their components as I think this is a logical way to structure code - I do the same with unit tests - but we understand that people have different opinions and as I said, you can certainly change the config to support whatever you need.

@bard
Copy link

bard commented Aug 24, 2020

The following worked for me. It removes the plugin that enforces the "under src/" rule.

module.exports = {
  stories: ['../src/components/*.stories.*'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-essentials',
  ],
  webpackFinal: (webpackConfig) => {
      const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
        ({ constructor }) =>
          constructor && constructor.name === 'ModuleScopePlugin',
      )

      webpackConfig.resolve.plugins.splice(scopePluginIndex, 1)
      return webpackConfig
    }
}

@willTastyMakers
Copy link

willTastyMakers commented Oct 27, 2020

@mrmckeb
Hi,
I just want to say, and perhaps suggest that StoryBook should review this opinion that often gets put forth by most StoryBook evangelist, associates etc.

'... keep stories alongside their components as I think this is a logical way to structure code - I do the same with unit tests ...'

From my experience, this concept put fourth by StoryBook is directly against a rationale that led most Frontend architects in in search of a system like StoryBook. Every project, I have been involved with, has wanted to develop an environment for separating components in one repo from the scaffolding in another repo of a frontend architecture solution.

Several versions ago, v3 or 4, a shop where I was developing finally got the issues worked out. We were able to use re-wire and webpack to sustain a front-end structure that would allow developer to create components in the storybook directory/repo, and import them into the scaffolding directory/repo seamlessly during development . When we were ready to release we pushed both our latest version of the repo's new and updated components, and the front-end scaffolding repo and let the build take place in the code pipeline, treaty the StoryBook component as a library module handle by package.json.

The 2 top reasons this was super useful:

  1. If components are create in a different directory than the main scaffolding, this means that I can create 2 different repos. One for my front-end scaffolding and one for the storybook components. There are many obvious benefits to this approaches no matter the size of the team. ( Portability, Testing, Versioning, just to name a few)

  2. Segmenting the code this way brings a 10 fold increase in speeding up testing. Seriously, ( when component code is interspersed through out an app and the app grows there are bound to be contours of the component that will change breaking code that has not been touch for some time.)

I stopped advocating for StoryBook as a front-end architect, when I began using TypeScript to build React applications and could not easily enable this standalone repo approach. As I recall the issue involved incompatibilities stemming from re-wire or other complexities that made just to hard to set this separate repo approach.

Once again, I am leading an effort where the UX folks really want to import their figma specs and images into StoryBook. I am going to give craco a go and see if I can recreate this. It would really be helpful if storybook had an example repo(s) of how this storybook standalone approach in one repo with an external repo could be approached. I have gone down the path of trying to use bit but that is just way to much overhead. Bits main advocacy stems from there understanding that this is what many developers want but can't achieve with storybook.

@mrmckeb
Copy link
Member

mrmckeb commented Nov 9, 2020

@willTastyMakers I'm sorry, I think you've misunderstood what we're advocating here.

We're not saying that you can't or shouldn't have a separate repo for components, and we're not saying that you can't place you stories where you want.

Specifically, perhaps unclearly, I've said:

  • We recommend stories alongside your components, so that you don't have a "stories" folder that has a whole tree of stories that feels disconnected from the actual component code. There are benefits to this, such as sharing code and stub/mock data with tests.
  • The CRA preset is designed to mimic the behaviour of CRA, where everything must be in the src folder.

I'm one of both the CRA and Storybook teams (although I've been less active lately) and I can assure you that there are a number of ways to make this work.

As an example, one of the projects we have in my company is a monorepo, and we have a shared components package in our monorepo. It has Storybook with TypeScript support.

For convenience, we added a root babel.config.js using the react-app preset. We use this for builds, and Storybook uses this:

module.exports = (api) => {
  api.cache(true);

  return {
    plugins: ['styled-components'],
    presets: [
      [
        'react-app',
        {
          flow: false,
          typescript: true,
        },
      ],
    ],
  };
};

Storybook now has built-in TypeScript support, but we wanted to just use our config based on CRA. The Storybook Webpack config looks like this, and lives in the package where the components live:

module.exports = ({ config }) => {
  const newConfig = config;
  newConfig.module.rules[0].test = /\.(mjs|jsx?|tsx?)$/;
  newConfig.module.rules[0].use[0].options.presets = [];
  newConfig.module.rules[0].use[0].options.plugins = [];
  newConfig.resolve.extensions = [...config.resolve.extensions, '.ts', '.tsx'];
  return newConfig;
};

I stopped advocating for StoryBook as a front-end architect.

With newer versions of Storybook, you actually get out-of-the-box support for TypeScript. Unfortunately, the reality is that some people will always need more than Storybook does out of the box.

In my company, we customise our configs as we want Storybook to share the build config for that package - to ensure things don't work in Storybook, and then fail in the app (and vice versa).

The CRA preset takes the same approach (by default) - if it doesn't work in CRA, it won't work in Storybook.

That doesn't mean we are refusing to add support for tools like craco/rewired/etc. @shilman and I have discussed this before and we're very open to adding support - we're very open to PRs to add support for one or many of these into the preset.

In the meantime, you can always override Storybook's default Webpack config (or even build a reusable preset to do that).

@christo8989
Copy link

This is my solution. Maybe could be better but it works.

I'm on @storybook/react v6.4.22

const path = require('path');

/**
 * NOTE: Override CRA.
 * CRA requires all files to be within the src folder.
 * Storybook is no exception with the latest version.
 * This overrides the webpack config that forces it.
 * https://github.com/storybookjs/storybook/issues/9514#issuecomment-679350377
 */
module.exports = (config) => {
  const ruleWithOneOf = config.module.rules.find(rule => !!rule && !!rule.oneOf)
  const isFound = ruleWithOneOf.oneOf.some(item => {
    if (
      Array.isArray(item.include) &&
      item.include.find(a => a.includes('/src'))
    ) {
      item.include.push(path.join(__dirname, '../stories'))
      return true;
    }

    return false
  })

  if (isFound) {
    console.log(`Removed CRA limitation to force storybook files to stay inside of '/src'.`)
  } else {
    console.error(`Could not find the rule that forces stories to exist inside of '/src'.`)
  }

  return config;
}
const addStoriesPathToCRA = require('./addStoriesPathToCRA');

module.exports = {
  ...,
  webpackFinal: async (config) => {
    addStoriesPathToCRA(config)
    
    // ...

    return config;
  },
}

@danieldram
Copy link

danieldram commented Jul 3, 2022

  webpackFinal: (webpackConfig) => {
      const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
        ({ constructor }) =>
          constructor && constructor.name === 'ModuleScopePlugin',
      )

      webpackConfig.resolve.plugins.splice(scopePluginIndex, 1)
      return webpackConfig
    }

@bard How do I donate money to you or your project. Thank you!

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

No branches or pull requests