storybook: Error: exports is not defined

I’m trying to use storybook for the first time, so I decided to follow the guides. I can get it working with the examples, but as soon as i pull in my own components i get exports is not defined. It doesn’t matter if I use the “Quick Start Guide” or the “Slow Start Guide (React)” I always get the same unhelpful error.

exports is not defined

ReferenceError: exports is not defined at Object.<anonymous> (http://localhost:6006/static/preview.bundle.js:43176:23) at webpack_require (http://localhost:6006/static/preview.bundle.js:679:30) at fn (http://localhost:6006/static/preview.bundle.js:89:20) at Object.<anonymous> (http://localhost:6006/static/preview.bundle.js:43132:76) at Object.<anonymous> (http://localhost:6006/static/preview.bundle.js:43142:30) at webpack_require (http://localhost:6006/static/preview.bundle.js:679:30) at fn (http://localhost:6006/static/preview.bundle.js:89:20) at loadStories (http://localhost:6006/static/preview.bundle.js:40160:3) at ConfigApi._renderMain (http://localhost:6006/static/preview.bundle.js:41134:20) at render (http://localhost:6006/static/preview.bundle.js:41092:17) at ConfigApi.configure (http://localhost:6006/static/preview.bundle.js:41117:9) at Object.<anonymous> (http://localhost:6006/static/preview.bundle.js:40164:68) at Object.defineProperty.value (http://localhost:6006/static/preview.bundle.js:40165:30) at webpack_require (http://localhost:6006/static/preview.bundle.js:679:30) at fn (http://localhost:6006/static/preview.bundle.js:89:20) at Object.window.STORYBOOK_REACT_CLASSES (http://localhost:6006/static/preview.bundle.js:38867:18) at webpack_require (http://localhost:6006/static/preview.bundle.js:679:30) at http://localhost:6006/static/preview.bundle.js:725:39 at http://localhost:6006/static/preview.bundle.js:728:10

That error doesn’t really help much, and when I look up the error I end up at some issues from last year all saying that this problem has been patched out… I know that it’s probably my component that is exported in some way that storybook doesn’t like. But since all I’m getting is exports is not defined (along with some mess of a stacktrace) its kind of hard to debug.

I’m using typescript and I’m compiling it with just plain old tsc.

//tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react",
    "declaration": true,
    "sourceMap": true,
    "outDir": "./dist",
    "esModuleInterop": true
  },
  "include": [
    "./src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

And then importing the compiled js into storybooks.

//index.stories.jsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';

import { MatrixEffect } from '../dist/index';

storiesOf('MatrixEffect', module)
  .add('100x100', () => 
    <MatrixEffect height={100} width={100} />
  );

Version

  • @storybook/react 3.4.0
  • @storybook/addon-actions 3.4.0
  • babel-core 6.26.0
  • react 16.3.0

What am I missing? (if there’s a way to just import the ts straight away then that would preferable. But since I haven’t found any official docs for it, this is what I’ve got so far)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 46
  • Comments: 83 (20 by maintainers)

Commits related to this issue

Most upvoted comments

I’m getting this error without using TypeScript, just vanilla JS

this issue can be fixed by adding the correct plugin in the .babelrc file, since the tsconfig file is configured to generate commonjs compatible modules, we need to use the proper plugin

{
	"env": {
		"test": {
			"plugins": ["instanbul"]
		}
	},
	"plugins": ["@babel/plugin-syntax-dynamic-import", "@babel/plugin-transform-modules-commonjs"]
}

This is what I have in my .babelrc file and everything is working fine, I have my tsconfig file with exactly the same options and values.

"@babel/core" “^7.1.0” "@storybook/react" ^4.0.0-alpha.2" "react" “^16.4.0”

Note: This solution works for another kind of modules https://babeljs.io/docs/en/next/plugins#modules

I had the exact same issue, and for me the solution was switching from using transform-es2015-modules-commonjs to @babel/plugin-transform-modules-commonjs on babel.config.js.

before

module.exports = {
    presets: [['@babel/preset-env', { modules: false }], '@babel/preset-react'],
    plugins: [
        'transform-es2015-modules-commonjs',
        '@babel/plugin-proposal-class-properties'
    ]
};

after

module.exports = {
    presets: [['@babel/preset-env', { modules: false }], '@babel/preset-react'],
    plugins: [
        '@babel/plugin-transform-modules-commonjs',
        '@babel/plugin-proposal-class-properties'
    ]
};

I’m running into this, in the browser I get exports is not defined but in the terminal I get `“export ‘default’ (imported as ‘[ComponentName]’) was not found in ‘@[namespace]/[package-name]’”

  • Using lerna
  • Storybook 3.4.7
  • Everything is fine for my components with no internal dependencies
  • If I try to import a module with a dependency on another package in project/packages the error shows up
  • I am running my build scripts, so it’s trying to pull in a common-js version of the package.

If I change the internal dependency’s package.json main config to the non-built source everything works

So there’s something wrong with storybook’s webpack config and importing cjs into es module code, or something …

My fix

So I realized I accidentally deleted my package.json “module” field that pointed to the ES module version of my builds, adding that back in makes everything work again. Still seems like storybook should be able to pull the cjs version, but my problem is solved 🤷🏽‍♂️

Maybe unrelated, but I was having this exports is not defined issue because of my custom babel.config.js, reading https://storybook.js.org/docs/configurations/custom-babel-config/ solved my particular problem.

For me the issue is caused with the recent changes to include babel-loader in 4.0.0.alpha. The default server webpack config could include your commonjs compiles (packages, workspaces): https://github.com/storybooks/storybook/blob/b2b73596f9dd97b4ba8c03340bd36f868e836772/lib/core/src/server/config/webpack.config.dev.js#L78 https://github.com/storybooks/storybook/blob/b2b73596f9dd97b4ba8c03340bd36f868e836772/lib/core/src/server/config/utils.js#L3

For me, a fix is to override the default plugin declare with a custom webpack.dev.js:

https://github.com/psychobolt/react-rollup-boilerplate/blob/d9cb9179cb7c00baab486646c504110bf7e2f50a/.storybook/webpack.config.js#L7

// exclude 'babel-loader' so we can override it later
...defaultConfig.module.rules.filter(rule => !(
    (rule.use && rule.use.length && rule.use.find(({ loader }) => loader === 'babel-loader'))
)),

https://github.com/psychobolt/react-rollup-boilerplate/blob/d9cb9179cb7c00baab486646c504110bf7e2f50a/.storybook/webpack.config.js#L11

{
  test: /\.jsx?$/,
  include: require('path').resolve('./'),
  exclude: /(node_modules|dist)/, // exclude any commonjs files
  loader: 'babel-loader',
},

Omitting include also fixes the issue and has no side effects for me.

We are using storybooks + lerna + typescript. What solved for us was mixing @i-like-robots with @psychobolt:

module.exports = (baseConfig, env, config) => {
    config.module.rules = config.module.rules.filter(rule => !(
        (rule.use && rule.use.length && rule.use.find(({ loader }) => loader === 'babel-loader'))
    ));
    config.module.rules.push({
        test: /\.(ts|tsx)$/,
        loader: require.resolve('babel-loader'),
        options: {
            sourceType: 'unambiguous',
            presets: [['react-app', { flow: false, typescript: true }]],
        },

    });
    config.resolve.extensions.push('.ts', '.tsx');
    return config;
};
TypeError: Cannot assign to read only property 'exports' of object '#<Object>'

This is most likely caused by Webpack wrapping a CommonJS module with its ESM wrapper. Webpack will use an ESM wrapper if it sees any usage of import in the module. It’s usually caused by either:

  1. Mixing and matching ESM and CJS in your source code
  2. Babel injecting ESM helpers into a CJS module

To avoid the second case you’ll need to set Babel’s sourceType to "unambiguous" to force it to check the module type first.

https://github.com/i-like-robots/broken-webpack-bundle-test-case


Update: My original comment is hidden above but this is the base configuration we have been using to resolve these issues across multiple monorepo projects:

const excludePaths = [/node_modules/, /dist/]

module.exports = ({ config }) => {
  // Use real file paths for symlinked dependencies do avoid including them multiple times
  config.resolve.symlinks = true

  // HACK: extend existing JS rule to ensure all dependencies are correctly ignored
  // https://github.com/storybooks/storybook/issues/3346#issuecomment-459439438
  const jsRule = config.module.rules.find((rule) => rule.test.test('.jsx'))
  jsRule.exclude = excludePaths

  // HACK: Instruct Babel to check module type before injecting Core JS polyfills
  // https://github.com/i-like-robots/broken-webpack-bundle-test-case
  const babelConfig = jsRule.use.find(({ loader }) => loader === 'babel-loader')
  babelConfig.options.sourceType = 'unambiguous'

  // HACK: Ensure we only bundle one instance of React
  config.resolve.alias.react = require.resolve('react')

  return config
}

TypeError: Cannot assign to read only property 'exports' of object '#<Object>'

I spent the day on this issue, I already had the sourceType: 'unambigous'.

For my part, it was not linked to a node_modules folder to ignore since it is a relative file right next to it.

A workaround that works for me is to force the option modules: 'cjs' for the @babel/preset-env.

I also have this problem with @storybook/react@next, the final solution for me was to manually add the babel plugin @babel/plugin-transform-modules-commonjs, while with the debug: true option on the @babel/preset-env I see that it is already used… I don’t understand but it works.

EDIT: This is not a solution because it loses the benefits of ESM modules with webpack. I need to force transform to cjs only for the storybook builds.

🎉 My .storybook/.babelrc: 🎉

{
  "extends": "../.babelrc",
  "plugins": [
    "@babel/plugin-transform-modules-commonjs"
  ]
}

I solved the issue by creating a .storybook/weback.config.js file containing the following:

const path = require('path');

// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
    // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    config.module.rules[0].use[0].options.sourceType = "unambiguous";

    return config;
};

Seems like it does boil down to the sourceType babel issue. I tried adding a .babelrc file (as suggested by @0nn0), but that seemed to replace the entire babel configuration rather than modify it, causing further issues.

[UPDATED] - We have to exclude node_modules from this rule otherwise it will break the build

I have resolved it by adding this rule in storybook main.js file

let rules = [{
  test: /\.(js|mjs|jsx|ts|tsx)$/,
  include: /dist/, //Include dist folder as well to parse using babel loader in order to resolve exports not defined error
  exclude: /node_modules/,
  loader: 'babel-loader',
  options: {
    presets: [
      ["@babel/preset-env", {
        modules: "commonjs"
      }]
    ]
  }
}]

Along with this, you may also need to disable the eslint validations for your dist folder, so for that, you can use below script

  webpackFinal: config => {

    //Find eslint loader rule from webpack config
    let eslintRule = config.module.rules.find(rule => {
      if (rule && rule.use) {
        return rule.use.some(use => use.loader.match('eslint-loader'))
      }
    });

    //Exclude validations of dist folder contents
    eslintRule.exclude = /dist/;

    return {
      ...config,
      module: {
        rules: [
          ...rules,
          eslintRule,
          ...config.module.rules
        ]
      }
    }
  }

Not sure if this will help anyone else but we fixed this issue by running the following:

npm i react-scripts -D

@ryanflorence I have the exact same lerna setup and the exports issue for storybook. I have a package which exposes the built version of the UI-Elements. Apologies but could you provide more details when you say, "module" field that pointed to the ES module version of my builds, adding that back in makes everything work again.

@sayjeyhi yeah, it should. This is not actually Storybook issue. This happens just because when you work in monorepo, you have node_modules not only in your project root, but in */packages as well, which is not excluded by default. (I actually not sure that it shouldn’t, because its monorepo organization specific. If you create your Storybook as package in Lerna packages folder you won’t have this issue)

So for my case I just did this in .storybook/webpack.config.js:

const path = require('path');
const glob = require('glob');

// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
    // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.
    // Make whatever fine-grained changes you need
    const babelLoader = config.module.rules[0];

    /**
     * Exclude pacakge's `node_modules` from Storybook babel processing.
     */
    glob.sync('./packages/*/node_modules').forEach(match => {
        babelLoader.exclude.push(path.resolve(match));
    });

    // Return the altered config
    return config;
};

Had the same issue, also due to removing module field. Adding @babel/plugin-transform-modules-commonjs to babel plugin helped, as described in this comment: https://github.com/storybooks/storybook/issues/3346#issuecomment-423719241

@skeet I wondered why storybook had the message

info => Using base config because react-scripts is not installed.
info => Using default webpack setup based on "create-react-app".
info => Using base config because react-scripts is not installed.

So, after installing react-scripts, it now says

info => Loading create-react-app config.
info => Using default webpack setup based on "create-react-app".
info => Loading create-react-app config.

I managed to fix the issue by adding the following line to the .babelrc file:

"sourceType": "unambiguous"

More info on this option: https://babeljs.io/docs/en/options#sourcetype Believe this option is only available with Babel 7 and up.

We have same issue, when r u going to fix it ?

We have also had the exports is not defined problem a few times and we’ve previously worked around it by overriding the Babel configuration as suggested by others.

But, I recently started to look into this again and I noticed that the exclude property for the default JS rule was being resolved to an absolute path (below is a console.log() of the generated Webpack config):

{
  test: /\.(mjs|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: '.cache/storybook',
        presets: [
          [
            '@babel/preset-env',
            { shippedProposals: true, useBuiltIns: 'usage' }
          ],
          '@babel/preset-react',
          '@babel/preset-flow'
        ],
        plugins: [
          'babel-plugin-macros',
          '@babel/plugin-proposal-class-properties',
          [
            'babel-plugin-react-docgen',
            { DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES' }
          ]
        ]
      }
    }
  ],
  include: ['/Users/matt.hinchliffe/Project/'],
  exclude: ['/Users/matt.hinchliffe/Project/node_modules']
}

I had assumed the exclude property should be a RegExp so I thought it looked odd! I realised that due to the structure of our project we actually have many node_modules folders so I tried updating this line to a RegExp (/node_modules/) - and it fixed it!

This avoids transpiling modules which have already been transpiled - and in particular avoids the useBuiltins option of preset-env from injecting core-js polyfills (removing the useBuiltins option or setting the environment to target runtimes which do not require any polyfills can also help to avoid this issue.)

So there are a few different issues at play which result in this problem:

  1. Dependencies in node_modules folders can be unintentionally transpiled by Babel
  2. The useBuiltins option can inject core-js polyfills into your code in the wrong format for the module type (see https://github.com/babel/babel/issues/7463 and https://github.com/babel/babel/issues/9187)
  3. If packages are being symlinked (such as in a monorepo) then you must tread extra carefully to avoid point 1!

Unfortunately it is not very easy to extend the existing exclude option, but it is possible!

I’ll try to take a look asap

@ndelangen ok, here’s the repro repo 😂

https://github.com/busticated/storybook-monorepo-repo

you should be able to simply:

  1. git clone
  2. npm i && npm start

…and see storybook attempt to load in the browser. open dev tools’ console and you’ll see the exports error.

couple of notes:

  • run npm run build to test the prepublish build
  • it should work across node / npm versions +/- some lock file noise (fwiw, i used node@8 and npm@5 to align w/ day job)
  • the last two commits add the "module": "src/index.jsx" fields to packages/*/packge.json files. if you revert those, you’ll see the original export 'default' (imported as 'Two') was not found webpack warning.

Sounds like I have the identical issue.

@busticated I’d be happy to take a look at a monorepo-repro-repo 🙈

It’s likely that:

  • some files are parsed through babel twice
  • some files are parsed though loaders that aren’t compatible with each other
  • some files are compiled using the wrong babel/ts config
  • some other monorepo shenanigans

Unfortunately ReferenceError: exports is not defined doesn’t tell us anything other then, something is not as it’s supposed to be.

Hey @aperkaz, I have updated the rule to exclude node_modules, I found that storybook was launching properly in dev mode however breaking in production mode because of this change. So I had to exclude node_modules in order to fix. You can take the latest from my updated comment above.

Huzzah!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.0.0-alpha.0 containing PR #8822 that references this issue. Upgrade today to try it out!

You can find this prerelease on the @next NPM tag.

Closing this issue. Please re-open if you think there’s still more to do.

@qrosmeli Thanks for the tip. You saved my day! 🚀

Sorry for bringing confusion, I’ve based my answer on Lerna configuration where required packages are hoisted to the root and installed there as dev dependencies. So I did’t experience the problem of parsing their node_modules.

It seems that some user have a use case where they have installed packages deeper in the tree like /lib/components/node_modules https://github.com/storybookjs/storybook/issues/3346#issuecomment-475437230 and babel-loader tries to parse them.

By default storybook excludes root node_modules but maybe it’s worth to exclude all of them.

https://github.com/storybookjs/storybook/blob/f7367b18ec7d6e077fba5b99da89233b63c4f280/lib/core/src/server/config/utils.js#L5-L6

https://github.com/storybookjs/storybook/blob/f7367b18ec7d6e077fba5b99da89233b63c4f280/lib/core/src/server/common/babel-loader.js#L1-L13

Seems to be fixed in version 5.2

I’m using Lerna, internal packages are bundled by Webpack with output libraryTarget: 'commonjs2'. Approach based on @JasonTheAdams comment works for me. I’ve also tested @0nn0 solution with babelrc { "sourceType": "unambiguous" } and it also works however it requires to have .babelrc in package root.

Some basic setup - maybe it will help someone 😉(Storybook: 5.1.10, Lerna: 3.16.4, Webpack: 4.39.1, Babel: 7.5.5)


file: lerna_repo/.storybook/webpack.config.js - doesn’t exist by default

module.exports = async ({ config }) => {
  const [ mjsjsx ] = config.module.rules;
  const [ babelLoader ] = mjsjsx.use;

  babelLoader.options.sourceType = 'unambiguous'

  return config;
};

file: lerna_repo/stories/index.stories.js

import defaultExport, { namedExport } from '../packages/examplePackage' // works locally
// import defaultExport, { namedExport } from '@examplePackage' // works installed
...

file: lerna_repo/packages/examplePackage/package.json

"name": "@examplePackage",
"version": "0.0.1",
"main": "./dist/index.js"
...

file: lerna_repo/packages/examplePackage/dist/index.js - generated by Webpack

module.exports=function(e){var n={};function...

I have created a reduced test case for this problem with information on how to avoid it. I will file an issue with Babel if necessary.

https://github.com/i-like-robots/broken-webpack-bundle-test-case

We also stumbled upon this issue and it took more more of a half a day fighting configs to figure it out what it might be. 😢

This is still happening for me in v4.0.0-alpha.20 with babel 7.0.0

If anyone is still encountering this, here’s what worked for me:

Perhaps because my Babel config is named babel.config.js instead of .babelrc, it seems like Storybook did not identify it. I had to configure Storybook to explicitly read my existing Babel config (https://storybook.js.org/docs/react/configure/babel#custom-configuration), so my main.js now looks like this:

const config = {
    stories: [
        "../stories/**/*.stories.tsx",
    ],
    addons: [
        "@storybook/addon-essentials",
    ],
    framework: "@storybook/react",
    core: {
        builder: "@storybook/builder-webpack5"
    },
    babel: async (options) => {
        // Ignoring the default Storybook options and loading our own:
        const opt = require('../babel.config');
        
        // I'm manually adding "@babel/preset-env" here since my personal setup doesn't 
       // specify it in the main Babel config file. You probably won't need this part.
        opt.presets.unshift(
            [
                "@babel/preset-env",
                {
                    "targets": {
                        "chrome": "108",
                    }
                }
            ]
        )
        return opt;
    },
}
export default config;

I also had to modify the React imports of the example from import React from 'react' to import * as React from 'react' but I guess it depends on your specific setup.

@pixeleate Would you mind sharing your working repo?

I can see that mostly everyone here with a monorepo project is using lerna, I have a monorepo project that uses yarn workspaces rather than lerna and everything is working fine with the latest version of storybook + typescript, and without strange webpack configurations, it should work fine as well with babel.

If you show some interest I can create a monorepo with a working storybook, I can see on the @busticated 's files, is that some scripts runs in the wrong order and some@ dependencies are in the incorrect package.json, I’m not saying that is causing issues but it could be.

Also want to chime in here. Using Storybook 5, Babel 7.4 (with core-js 3), TypeScript 3.4 and a monorepo. Most of these suggestions did not work 100%, but something I realized did. The very nature of monorepos is that a package is importing the “built” files from another package, not the source files, which is true when in the NPM registry/node module layer, but in development, is quite annoying. To get around this, I defined Webpack aliases that forwarded lib/ to src/, and everything just worked, especially since all code is now ESNext/ESM!

Here’s the hack:

glob.sync(path.join(__dirname, '../packages/*/package.json')).forEach(filePath => {
  const { name } = require(filePath);

  config.resolve.alias[`${name}$`] = `${name}/src`;
  config.resolve.alias[`${name}/lib`] = `${name}/src`;
});

And to get Babel + TS working, I opted to mutate the existing babel-loader instead of adding a new one, as my local Babel config isn’t 100% compatible with Storybook’s, but their own config is.

const babelConfig = config.module.rules[0];

// Replace Flow with TypeScript
babelConfig.test = /\.(j|t)sx?$/;
babelConfig.exclude.push(/node_modules/);
babelConfig.use[0].options.sourceType = 'unambiguous';
babelConfig.use[0].options.presets[2] = require.resolve('@babel/preset-typescript');
babelConfig.use.unshift({ loader: require.resolve('react-docgen-typescript-loader') });

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

@tmeasday Got it. I’m starting to wrap my head around this issue. What’s tricky is that, in my situation, I actually do want it to compile the child node_modules as that’s where I’m developing the components themselves, treating it as a separate package.

I think @skeet’s suggestion, as echoed by @jcousins-ynap, is probably the best solution here. We don’t want Storybook to make assumption on how sub-packages are handled (i.e. ignoring their node_modules). If someone didn’t want the sub-modules node_modules compiled, they likely wouldn’t have installed the package dependencies to begin with.

It seems to all come down to babel + webpack’s ability to recognize CommonJS vs ES6 modules, which doesn’t seem to be perfect. Adding the "module": field to the sub-package’s package.json explicitly informs babel that the package uses ES6 modules, which is the safest way to approach this.

Thank you for your attention to this!

After applying @skeet’s suggestion (https://github.com/storybooks/storybook/issues/3346#issuecomment-459308703) the issue returned when I started referencing one package as a dependency (not peer or dev) of a few others.

Putting the module field into the dependency’s package.json as in @ryanflorence’s fix (https://github.com/storybooks/storybook/issues/3346#issuecomment-415982589) did the job.

   main: "dist/index.js",
+  module: "dist/index.js",

Just to drive by on this one without fully understanding what people’s issues are (apologies!) – here’s a snippet from my webpack config that works around this issue, maybe in a simpler way:

  const babelLoader = storybookBaseConfig.module.rules[0];
  babelLoader.exclude.push(
    path.resolve('./lib/components/node_modules'),
    /* etc */
  );

I removed the babel loader from webpack.config.js in the .storybook folder and it works fine now. I don’t use Typescript though.

I just ran into an issue with the same error message in a storybook after turning on yarn workspaces in a lerna project. I suspect that this is caused by package loading issues. Investigating further.

I’m getting export 'MatrixEffect' was not found in '../dist/index' in the terminal. But I can import the module in just a plain node runtime (can’t use it ofc, but at least i know it can be imported).