Bit: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Created on 13 Jan 2020  路  15Comments  路  Source: teambit/bit

Description

I just integrated bit into my project, when I build my components everything is going well and I don't get errors but when I see them on the platform I get the following error in the overview section...

Element type is invalid: expected a string (for built-in components) or a class/function 
(for composite components) but got: undefined. You likely forgot to export your component 
from the file it's defined in, or you might have mixed up default and named imports.

Specifications

  • Bit version: 14.7.1
  • Node version: 12.11.0
  • npm / yarn version: 6.11.3/1.17.3
  • Platform: MacOS
  • Bit compiler (include version): [email protected]
  • Bit tester (include version): not apply

Context and additional information

My component:

import React from 'react';
import ReactMarkdown from 'react-markdown';
import MarkdownLinkRenderer from '~components/utils/MarkdownLinkRenderer';
import { ReactComponent as helpIcon } from '~assets/icons/info-circular-button.svg';
import { ReactComponent as exclamationIcon } from '~assets/icons/exclamation.svg';
import { ReactComponent as closeIcon } from '~assets/icons/close.svg';
import { ReactComponent as checkIcon } from '~assets/icons/checked.svg';

const iconTypes = {
  help: helpIcon,
  error: exclamationIcon,
  success: checkIcon,
  close: closeIcon,
};

const renderIcon = (type = 'help') =>
  React.createElement(iconTypes[type], { className: 'help-icon' });

class Help extends React.Component {
  constructor(props) {
    super(props);
    this.spanRef = React.createRef();
    this.state = {
      currentTooltipPosition: {},
    };
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, false);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll, false);
  }

  onMouseHover = () => {
    const { type, right } = this.props;
    if (this.spanRef && this.spanRef.current && type === 'error' && right) {
      const currentPosition = this.spanRef.current.getBoundingClientRect();
      this.setState({
        currentTooltipPosition: {
          top: currentPosition.top + 2,
          left: currentPosition.left + 30,
          position: 'fixed',
        },
      });
    }
  };

  handleScroll = () => {
    const { type, right } = this.props;
    if (this.spanRef && this.spanRef.current && type === 'error' && right) {
      this.setState({
        currentTooltipPosition: {
          display: 'none',
        },
      });
    }
  };

  textToRender = text => {
    return Array.isArray(text) ? (
      text
    ) : (
      <ReactMarkdown source={text} renderers={{ link: MarkdownLinkRenderer }} />
    );
  };

  render() {
    const { props, state, spanRef, onMouseHover, textToRender } = this;
    const { text, modal, type, bottom, right, left, styles } = props;
    const { currentTooltipPosition } = state;
    const spanClassNames = [
      'help-text',
      type === 'error' && 'help-error-text',
      right && 'right',
      bottom && 'bottom',
      left && 'left',
      styles && styles.helpText,
    ].filter(Boolean);

    return (
      <div
        className={`help ${modal ? 'help-modal' : ''}`}
        data-testid={`${modal ? 'wrapped-input-help-modal' : 'wrapped-input-help'}`}
      >
        <div
          ref={spanRef}
          onMouseEnter={onMouseHover}
          className={`help-icon-container ${(styles && styles.helpIcon) || ''}`}
        >
          {renderIcon(type)}
          <span style={currentTooltipPosition} className={spanClassNames.join(' ')}>
            {textToRender(text)}
          </span>
        </div>
      </div>
    );
  }
}

export default Help;

typhelp wanted

Most helpful comment

Hello,
I've got a similar problem with using svgs.
I import them like this

import { ReactComponent as VisibilityIcon } from './../assets/visibility.svg';

I tried to remove the compiler on them like

  "bit": {
    "env": {
      "compiler": "bit.envs/compilers/[email protected]"
    },
    "componentsDefaultDirectory": "components/{name}",
    "packageManager": "npm",
    "overrides": {
      "*": {
        "dependencies": {
          "graphql": "^14.5.8"
        },
        "peerDependencies": {
          "react": "^16.9.0",
          "react-dom": "^16.9.0"
        }
      },
      "auth/assets/*": {
        "env": {
          "compiler": "-"
        }
      }
    }
  }

Please help 馃槙

All 15 comments

I believe it's a result of react / react-dom are dependencies of your component which makes a duplicate instance of them in the playground. you should make them a peer deps by using overrides.
See more here:
https://docs.bit.dev/docs/react-guidelines#add-react-libraries-as-peer-dependencies-with-relaxed-versions
If they are already defined as peer only (you can see it both in the bit.dev dependencies tab or using bit show [comp-id]. please share your example / component if you can so we can take a look.

@GiladShoham Thank you very much for the reply.

I already have them as peer deps, I share the link to the component
https://bit.dev/deividzavala/runa-spa-mx/help?example=5e1df738193a35001a2e3f85

Hey @DeividZavala, can you please write an example of how to use your component?

Hey @JoshK2, sure.

Right now I have the following case, the component is an icon that shows me a message with a tooltip ... something simple. It is used as a component that is part of the application itself, as follows:

import Help from '~components/forms/Help';

...
<td className='error-modal-text'>
      <Help
          className='help-text'
          text="example text"
          type='error'
          right
       />
 </td>
...

When integrating bit to share the components, I follow all the steps and I have no error, I run first
bit add componente-path then bit status if I have to add dependencies of the component I add them, if not the case continues with bit build in this step there seems to be no error but I don't know if it has to do with the compiler that I am using that is [email protected], then I run bit tag --all and finally I export the component and this is where I have the error in the overview section

I did a test with the component, set up a new project with the create-react-app and install the component with yarn but I had the same error.

import React from "react";
import Help from '@bit/deividzavala.runa-spa-mx.help'

function App() {
  return (
    <div className="App">
      <Help text="demo text" />
    </div>
  );
}

I checked the files generated by the bit build command and there seems to be no errors in them.

I add my package.json configuration if it helps

"bit": {
    "env": {
      "compiler": "bit.envs/compilers/[email protected]"
    },
    "componentsDefaultDirectory": "components/{name}",
    "packageManager": "yarn",
    "resolveModules": {
      "aliases": {
        "~assets": "./src/assets",
        "~components": "./src/components"
      }
    },
    "overrides": {
      "*": {
        "peerDependencies": {
          "react": "^16.12.0",
          "react-dom": "^16.12.0"
        }
      },
      "./src/assets/*": {
        "env": {
          "compiler": "-"
        }
      },
      "src/*.scss": {
        "env": {
          "compiler": "-"
        }
      }
    }
  }

Thank you very much for the help.

It might be a result of yarn deleting bit's links. Can you try in a new cra app from scratch using npm instead of yarn?

Hey @DeividZavala, I tried to install the component but I get an error of not found in one of your dependencies:
https://bit.dev/deividzavala/runa-spa-mx/markdown-link-renderer/

I already did it and had the same result, the component doesn't work, even i use npm as package manager with the CRA project

@JoshK2 I made some changes for the tests, but the component is already up and running.
link: https://bit.dev/deividzavala/runa-spa-mx/markdown-link-renderer
Thank you for the help, i'll be trying to figure out what's missing

Hello Guys
After a lot of tests and modifications i think found the issue.

it seems to be the svgs, in my component i have a complementary function that returns an svg as a React components depending of a type parameter as follows:

const iconTypes = {
  help: HelpIcon,
  error: ExclamationIcon,
  success: CheckIcon,
  close: CloseIcon
};

const renderIcon = (type = "help") => {
  const IconComponent = iconTypes[type];
  return <IconComponent className="help-icon" />;
};

my imports are the following:

import { ReactComponent as HelpIcon } from "~assets/icons/info-circular-button.svg";
import { ReactComponent as ExclamationIcon } from "~assets/icons/exclamation.svg";

and i'm using it like this:

...
<div
        ref={spanRef}
        onMouseEnter={onMouseHover}
        className={`help-icon-container ${(styles && styles.helpIcon) || ""}`}
      >
        {renderIcon(type)} // here
        <span
          style={currentTooltipPosition}
          className={spanClassNames.join(" ")}
        >
          {textToRender(text)}
        </span>
</div>
....

Reading the docs i saw that assets (svgs in this case) must not be passed through the compiler so i added the following config to my package.json.

...
    "overrides": {
      "*": {
        "peerDependencies": {
          "react": "^16.12.0",
          "react-dom": "^16.12.0"
        }
      },
      "./src/assets/*": {
        "env": {
          "compiler": "-"
        }
      },
      "src/*.scss": {
        "env": {
          "compiler": "-"
        }
      }
    }
...

So my questions is, Am i doing well?
If not, what can i do?

thanks for your help :D

@DeividZavala Can you please verify that after the overrides configuration, the compiler is not applied to the relevant components?
run bit show [component-id] and make sure the compiler is empty.

@GiladShoham Done, my svg icons were added as part of the help component so i add another one that is independent and the compiler is shown in the details :/

The original component info:
help info

The independent svg:
late info

As I see in the picture, the SVG component still has the compiler (which is not your desire result).
I would recommend adding all the svgs with a namespace (icon / assets / sggs or what ever fits).
Then in the override use it with:

"namespace/*": {
        "env": {
          "compiler": "-"
        }
      }

For testing purposes, you can add a specific component in the overrides and make sure it has no compiler just to verify that the compiler is your issue.

I just removed all the components part of help components and add them again as independent ones with the namespace as you suggest, the part of the compiler works, it is no longer shown in the details but the Help components still not working.

This is my repo: https://github.com/DeividZavala/runa-components

icons

@DeividZavala We will check it.
@JoshK2 FYI

Hello,
I've got a similar problem with using svgs.
I import them like this

import { ReactComponent as VisibilityIcon } from './../assets/visibility.svg';

I tried to remove the compiler on them like

  "bit": {
    "env": {
      "compiler": "bit.envs/compilers/[email protected]"
    },
    "componentsDefaultDirectory": "components/{name}",
    "packageManager": "npm",
    "overrides": {
      "*": {
        "dependencies": {
          "graphql": "^14.5.8"
        },
        "peerDependencies": {
          "react": "^16.9.0",
          "react-dom": "^16.9.0"
        }
      },
      "auth/assets/*": {
        "env": {
          "compiler": "-"
        }
      }
    }
  }

Please help 馃槙

hello @GiladShoham @JoshK2, is there any solution for this issue?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KutnerUri picture KutnerUri  路  12Comments

yairEO picture yairEO  路  19Comments

ranm8 picture ranm8  路  16Comments

itaymendel picture itaymendel  路  10Comments

itaymendel picture itaymendel  路  16Comments