Storybook: Storybook 4 error: cannot assign to read only property 'exports' of object '#<Object>'

Created on 9 Sep 2018  路  18Comments  路  Source: storybookjs/storybook

Bug or support request summary

Storybook 4, Webpack 4, Babel 7 throws this error after running yarn storybook:

image

It looks like Storybook/Webpack is parsing content from the react directory in the node_modules directory of my shared-components package.

Steps to reproduce

Run yarn storybook in project directory and then visit http://localhost:6006/.

Please specify which version of Storybook and optionally any affected addons that you're running

  • @storybook/addon-actions 4.0.0-alpha.21
  • @storybook/addon-links 4.0.0-alpha.21
  • @storybook/addons 4.0.0-alpha.21
  • @storybook/cli 4.0.0-alpha.21
  • @storybook/react 4.0.0-alpha.21

Affected platforms

  • @babel/cli 7.0.0
  • @babel/core 7.0.0
  • react 16.5.0
  • react-dom 16.5.0

Code Snippets

.storybook/webpack.config.js

module.exports = {
  plugins: [
  ],
  module: {
    rules: [
      {
        test: /.js?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader',
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg|jpe?g|gif)$/,
        loader: 'url-loader?limit=100000',
      },
    ],
  },
};

babel.config.js

module.exports = function (api) {
  const presets = ["@babel/preset-flow", "@babel/preset-react"];
  const plugins = ["@babel/plugin-transform-strict-mode", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-function-bind", "@babel/plugin-proposal-object-rest-spread"];

  api.cache(true);

  return {
    presets,
    plugins
  };
}

index.stories.js

import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Button from '../shared-components/button/src/components/Button';

storiesOf('Button', module)
  .add('Primary, link, target blank', () => (
    <Button actionType='link' action='https://google.com' target='_blank' style='primary' name='Hello world' />
  ))
  .add('Primary, Callback', () => (
    <Button actionType='callback' action={action('button-click')} style='primary' name='Hello world' />
  ))
  .add('Secondary, link', () => (
    <Button actionType='link' action='https://google.com' style='secondary' name='Hello world' />
  ))
  .add('Action, link', () => (
    <Button actionType='link' action='https://google.com' style='action' name='Hello world' />
  ));

Button.js

import React from 'react'; // eslint-disable-line no-unused-vars

import '../styles/button.css';

const Button = (props) => {
  if (props.actionType !== 'link' && props.actionType !== 'callback') {
    return 'Unrecognized action type';
  }

  return (
    props.actionType === 'link' ?
        <a href={props.action} target={props.target} className={`df-button ${props.style}`}>
          {props.name}
        </a> :

        <button onClick={props.action} className={`df-button ${props.style}`} >
          {props.name}
        </button>
  );
};

export default Button;
babel / webpack has workaround question / support

Most helpful comment

I had to go through all rules and exclude node_modules. Guess it depends on which node modules you have installed in your packages.

       // Exclude node_modules, otherwise storybook will throw runtime errors
        var nodeModules = /.*\/packages\/.*\/node_modules/;
        console.log('Excluding files:', nodeModules);

        config.module.rules.forEach(rule => {
          if (rule.exclude) {
            rule.exclude.push(nodeModules);
          } else {
            rule.exclude = [nodeModules];
          }
        });

        return config;

All 18 comments

Is this a monorepo ?

Why did you add this rule? :

     {
        test: /.js?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },

@igor-dv

Thanks for the quick reply!

It is a monorepo.

Looking at this today it looks like the easiest solution might be to just not include node_modules in each component's subdirectory?

Here's the directory structure:

- monorepo
- - .storybook
- - stories
- - - index.stories.js
- - node_modules
- - component1
- - - package.json
- - - node_modules
- - - src
- - component2
- - - package.json
- - - node_modules
- - - src
...

The babel-loader rule is for compiling JSX into Javascript. But it seems like webpack is trying to compile the node_modules in each component sub-directory, instead of just the files in the src directories of each component?

The babel-loader rule is for compiling JSX into Javascript.

Storybook already contains this rule. Try to use "full control mode" to modify webpack to something like this:

//.storybook/webpack.config.js
module.exports = (config) => {
  const jsRule = config.module.rules.find(/* find existing js rule */);
  jsRule.exclude = /node_modules/
}

Thanks, looks like that will do the trick along with removing some of the node_modules in our subdirectories. Appreciate the help!

I had to go through all rules and exclude node_modules. Guess it depends on which node modules you have installed in your packages.

       // Exclude node_modules, otherwise storybook will throw runtime errors
        var nodeModules = /.*\/packages\/.*\/node_modules/;
        console.log('Excluding files:', nodeModules);

        config.module.rules.forEach(rule => {
          if (rule.exclude) {
            rule.exclude.push(nodeModules);
          } else {
            rule.exclude = [nodeModules];
          }
        });

        return config;

@fyyyyy Yeah this helped me going through this issue using @storybook/web-components with any imported components from other authors; probably should be done by default?

//cc @shilman

@fyyyyy @lozandier that's pretty weird. can you explain a bit more about what's going on and why this fixes it and what code should do this? Core? Web-components framework code? I'm still trying to wrap my head around it. Thanks! 馃檹

This happened in a lerna monorepo, where /packages/... contained various web components with frameworks like stencil, vue etc. Not sure which node module under /packages/... caused the issue but anyhow i think storybook should exclude node_modules by default.

cc @ndelangen @mrmckeb

In theory, every package in node_modules should be in CJS or ESM format, and should not need processing. In reality, that's fairly accurate - but a notable part of the community want to also be able to process packages... Sometimes we get requests for this for CRA too (which we reject for the overhead it adds).

So my view is that by default, we should exclude node_modules, and make users change it if they want - but I fear this would negatively impact a group of people that I can't quantify.

I agree, this could be a breaking change for some people.
So providing a config option like : excludeNodeModules which is false by default may be a first step. Then later on, you can decide to make it true by default.

Oh, and better error handling may help.

We can make breaking changes, especially with majors - I think it's late for v6 though. @shilman what do you think?

@mrmckeb I think we can make breaking changes up until RC if it鈥檚 the right thing to do. I don鈥檛 really understand the tradeoffs here or why it was processing node_modules to begin with cc @ndelangen

@shilman Just to confirm, I indeed had a similar use case as @fyyyyy (a component mono-repo directory structure for a suite of components)

We changed the exclude pattern in v6 already, I'd assume this to be fixed in 6.0, is this not the case? What version is this bug report for?

we were using "latest", so "version": "5.3.19"

Would you be able to verify this is fixed in v6 beta?

Seems fixed in 6.0.21

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xogeny picture xogeny  路  3Comments

MrOrz picture MrOrz  路  3Comments

sakulstra picture sakulstra  路  3Comments

levithomason picture levithomason  路  3Comments

miljan-aleksic picture miljan-aleksic  路  3Comments