Storybook: Decorators syntax usage is broken

Created on 13 Mar 2019  路  23Comments  路  Source: storybookjs/storybook

Describe the bug
When trying to write a story that contains code using decorators syntax (In this case Mobx - the decorators works totally fine in the project) it throws an error:

index.js:39 Error: Decorating class property failed. Please ensure that proposal-class-properties is enabled and set to use loose mode. To use proposal-class-properties in spec mode with decorators, wait for the next major version of decorators in stage 2.

The babel configuration in .babelrc is correct, the file is read:

{
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    "babel-plugin-styled-components",
    "@babel/plugin-proposal-export-default-from",
    "@babel/plugin-transform-async-to-generator",
    "@babel/plugin-transform-classes",
    "@babel/plugin-transform-runtime"
  ],
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "modules": false
      }
    ],
    "@babel/preset-react"
  ],
}

To Reproduce
Steps to reproduce the behavior:

  1. Create story using the decorator
  2. Try open it - error in the console

Expected behavior
Decorators can be used.

System:

  • OS: Ubuntu
  • Framework: react
  • Addons: [actions, viewport]
  • Version: 5.0.1
babel / webpack has workaround inactive question / support

Most helpful comment

This likely has to do with legacy implementation of @babel/plugin-proposal-decorators. I'm working on a project using the latest decorator proposal and everything works fine:

['@babel/plugin-proposal-decorators', {
    legacy: false,
    decoratorsBeforeExport: false,
    version: 'jan-2019'
}]

All 23 comments

This likely has to do with legacy implementation of @babel/plugin-proposal-decorators. I'm working on a project using the latest decorator proposal and everything works fine:

['@babel/plugin-proposal-decorators', {
    legacy: false,
    decoratorsBeforeExport: false,
    version: 'jan-2019'
}]

I've tried to set up this and I got another error:

Error: [mobx] Incorrect decorator invocation. @observable decorator doesn't expect any arguments

Can not use the new decorator's implementation because of https://github.com/mobxjs/mobx/issues/1352.

@mweststrate maybe you have a solution for this one?

legacy should be true. Beyond that, share setup and example or didn't happen.

There you go - https://github.com/darkowic/storybook-mobx-decorators-example

I was able to reproduce it in react-create-app based example.

Thanks!

@darkowic this is not what maintainers typically call a minimal reproduction ;-). Can you link to the babel config in that repo?

_Edit: or is a blank storybook that large? Sorry, zero experience with storybook, just wanted to peek at the babel config to see if there is something obvious_

Well :D Actually what I post in the first commit is IMHO the minimal babelrc config that reproduces the problem.

In the repo is only ejected CRA, initiated storybook with https://github.com/storybooks/storybook/tree/next/app/react and added babel config to package.json

  "babel": {
    "plugins": [
      [
        "@babel/plugin-proposal-decorators",
        {
          "legacy": true
        }
      ],
      [
        "@babel/plugin-proposal-class-properties",
        {
          "loose": true
        }
      ]
    ],
    "presets": [
      "react-app"
    ]
  }

The actual code that reproduces it is in src/stories/index.js and it is simply:

class Test {
  @observable x = 1
}

const xxx = new Test();

There have to be something with storybook internals, I guess. Probably MobX itself is doing nothing wrong here. I ping you after @pgoforth comment because I thought that maybe you've seen similar case before. Let's wait for some maintainers answer @shilman

Looks superficially fine (assuming it is using babel 7, not 6). Maybe the config is not picked up at all from that place? Anyway, leaving it to the storybook maintainers for now... :)

I forgot about it - storybook does not read config from package.json but it does read from .babelrc - https://storybook.js.org/docs/configurations/custom-babel-config/

I've updated the example. The issue still there.

@darkowic
I don't know what to tell you. I can use decorators on static properties in my codebase and everything works fine in Storybook. However, I am not using Mobx and I am using the latest decorators spec. This seems like more of an incompatibility between Mobx (or a dependency thereof) and Storybook.

I did notice one thing. When using @babel/plugin-proposal-class-properties in loose mode, it does not use Object.defineProperty. That may have some bearing on the effectiveness of decorators, since they are used for modifying property descriptors. Hopefully this leads you in the right direction, but like @mweststrate implied, without code to test against, we can only guess what's causing the issue.[Update] Looking through your repo now

@darkowic note that error in the screenshot actually signals that it should be in loose mode, which is also in your config, which seems to suggest the config isn't actually picked up? MobX requires loose mode, that is correct. It seems that that is what storybook expects as well from the above message.

(loose mode is also the typescript behavior, and with loose mode it is easier to change descriptors with decorators, which is harder in strict mode, which seems to be a problem with the spec that sadly not everybody agrees upon, but it's on hold now anyway)

The config is picked. When I break anything in the babel config, storybook will throw that cannot read the config.

@darkowic
When I use this in your babel config in that test repo, the error is gone:

{
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": false,
        "decoratorsBeforeExport": false,
        "version": "jan-2019"
      },
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ]
  ],
  "presets": [
    "react-app"
  ]
}

I realize you need to use legacy decorators, but maybe there's a different legacy config that will work for you.

You guys are awesome, not sure what to add here. I'm working on some tools/process for debugging webpack issues right now https://github.com/storybooks/storybook/issues/6081. Hopefully it will help but this is fundamentally complex stuff 馃槮

@shilman @darkowic @mweststrate
Seems this is an issue with Babel
https://github.com/babel/babel/issues/7373

Just met the same issue with create-react-app created React projects.

The issue is about the order of overriding options passed to babel-loader. If it is a create-react-app project, @storybook/react would detect if react-scripts is present. If yes, it will load the options from react-scripts package. As you might know, react-scripts from create-react-app has configured babel options as below.

{
  "plugins": [
    ["@babel/plugin-proposal-decorators"],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }],
  ]
}

The default option for @babel/plugin-proposal-decorators is with legacy flag false.

The babel configuration from react-scripts come after customized storybook .babelrc. That is why .babelrc from storybook is not picking the legacy flag.

The work-round for me is to eject create-react-app project for now. After ejection, react-scripts is no longer there.

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!

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!

@darkowic I can't tell if you found the solution to your issue, but I was experiencing the same problem.

After struggling for a while, I found this comment https://github.com/babel/babel/issues/8577#issuecomment-439579410 which helped lead me to the solution that worked for me.

Adding the plugins to .babelrc was not enough. I needed to create a custom .storybook/webpack.config.js and add the plugins there. Once I had the custom webpack config, the error was gone and the stories were working properly.

FYI: Storybooks 5.1 solved the issue in my project. Though, I did not test it in the repository I created.

I have got a solution :smile:

Try add to .storybook/webpack.config.js

module: {
  rules: [
    {
      test:    /\.jsx?$/,
      exclude: /(node_modules)/,
      use:     'babel-loader',
    },
  ]
}

After this common babel config got applied.

@pgoforth

Should it be in place in default .storybook/webpack.config.js?
Initial setup of mine .storybook was made by teammate, so I don't know exact reason why babel-loader was absent.

I'm also using create-react-app, mobx and storybook and having issues with decorators.

I managed to get around this by having duplicate .babelrc files.
The first babelrc is in my root directory contianing:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }],
    "babel-plugin-styled-components"
  ],
  "presets": [
    "babel-preset-react-app"
  ]
}

The second .babelrc file I put in my .storybook directory looks like:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }, "p1"],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }, "p2"],
    ["babel-plugin-styled-components", {},  "p3"]
  ],
  "presets": [
    ["babel-preset-react-app", {}, "p4"]
  ]
}

I had to give everything alias name so it didn't clash with the root level babelrc.

So far things look good....

I'm also using create-react-app, mobx and storybook and having issues with decorators.

I managed to get around this by having duplicate .babelrc files.
The first babelrc is in my root directory contianing:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }],
    "babel-plugin-styled-components"
  ],
  "presets": [
    "babel-preset-react-app"
  ]
}

The second .babelrc file I put in my .storybook directory looks like:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }, "p1"],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }, "p2"],
    ["babel-plugin-styled-components", {},  "p3"]
  ],
  "presets": [
    ["babel-preset-react-app", {}, "p4"]
  ]
}

I had to give everything alias name so it didn't clash with the root level babelrc.

So far things look good....

@richardwardza Tried every solution around and yours is the only one that worked for me, Thaks a Lot!!

Was this page helpful?
4 / 5 - 1 ratings