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

Only default export (as string) is available for SVG files runtime after bit start is executed #4462

Closed
dimo-ivanov opened this issue Jun 23, 2021 · 16 comments · Fixed by #4595
Assignees
Labels

Comments

@dimo-ivanov
Copy link

dimo-ivanov commented Jun 23, 2021

Describe the bug

Using @svgr/webpack should provide an alternative export of an SVG file as a ReactComponent.
Afrer executing bit start there is an error/warning

ModuleDependencyError: Can't import the named export 'ReactComponent' (imported as 'SomeIcon') from default-exporting 
module (only default export is available)

Steps to Reproduce

Exporting an SVG as a ReactComponent option is declared by `react-scripts' like this

declare module '*.svg' {
  import * as React from 'react';
  export const ReactComponent: React.FunctionComponent<React.SVGProps<
    SVGSVGElement
  > & { title?: string }>;
  const src: string;
  export default src;
}
  1. Add react-app-env.d.ts file
/// <reference types="react-scripts" />

to make the ReactComponent from SVG available.

  1. Import an SVG file in another component like this
import { ReactComponent as SomeIcon } from './some-icon.svg'

and use it in the component as a component

return (
  <div>
    <SomeIcon />
  </div>
)
  1. Execute bit start
  2. Error message is being logged:
ModuleDependencyError: Can't import the named export 'ReactComponent' (imported as 'SomeIcon') from default-exporting 
module (only default export is available)

Expected Behavior

Imported SVG file should be available as a ReactComponent runtime (after executing bit start)

Specifications

  • Bit version: 0.0.428
  • Workspace type: harmony
  • Node version: 14.15.5
  • npm version: 7.17.0
  • Platform: macOS Big Sur 11.4, M1 chip

for harmony workspace

/**
 * this is the main configuration file of your bit workspace.
 * for full documentation, please see: https://harmony-docs.bit.dev/workspace/configurations
 **/ {
  "$schema": "https://static.bit.dev/teambit/schemas/schema.json",
  /**
   * main configuration of the Bit workspace.
   **/
  "teambit.workspace/workspace": {
    /**
     * the name of the component workspace. used for development purposes.
     **/
    "name": "touche",
    /**
     * set the icon to be shown on the Bit server.
     **/
    "icon": "https://static.bit.dev/bit-logo.svg",
    /**
     * default directory for all components in workspace, the following placeholders are available:
     * name - component name includes namespace, e.g. 'ui/button'.
     * scopeId - full scope-id includes the owner, e.g. 'teambit.compilation'.
     * scope - scope name only, e.g. 'compilation'.
     * owner - owner name in bit.dev, e.g. 'teambit'.
     **/
    "defaultDirectory": "{scope}/{name}",
    /**
     * default scope for all components in workspace.
     **/
    "defaultScope": "touche.panel-ui"
  },
  /**
   * main configuration for component dependency resolution.
   **/
  "teambit.dependencies/dependency-resolver": {
    /**
     * choose the package manager for Bit to use. you can choose between 'yarn', 'pnpm'
     */
    "packageManager": "teambit.dependencies/pnpm",
    "policy": {
      "dependencies": {
        "@hot-loader/react-dom": "17.0.1",
        "@svgr/webpack": "5.5.0",
        "@testing-library/react": "11.2.7",
        "@types/react-alert": "5.2.0",
        "classnames": "2.3.1",
        "moment": "2.29.1",
        "react-alert": "7.0.3",
        "react-scripts": "4.0.3"
      },
      "peerDependencies": {
        "react": "17.0.2",
        "react-dom": "17.0.2"
      }
    },
    "packageManagerArgs": [],
    "devFilePatterns": ["**/*.spec.ts"],
    "strictPeerDependencies": true
  },
  /**
   * workspace variants allow to set different subsets of configuration for components in your workspace.
   * this is extremely useful for upgrading, aligning and building components with a
   * new set of dependencies.
   **/
  "teambit.workspace/variants": {
    "panel-ui/custom-templates": {
      "teambit.harmony/aspect": {}
    },
    /**
     * "*" is a special rule which applied on all components in the workspace.
     **/
    "*": {
      /**
       * uncomment to apply the react environment on all components.
       **/
      "teambit.react/react": {}
    }
    // "panel-ui/components.general.header-notification-list-item": {
    //   "panel-ui/env": {}
    // }
  },
  "teambit.generator/generator": {
    "aspects": ["touche.panel-ui/custom-templates"]
  }
}
@EtheveDamien
Copy link

EtheveDamien commented Jun 23, 2021

Something similar when I import font or svg by css inside my react component.

@GiladShoham GiladShoham self-assigned this Jun 23, 2021
@dimo-ivanov
Copy link
Author

any news here?
I really need an svg as a react component! I got nested components which consume svg icons. Passing the icon as prop in create react app works, but with nested components passing the icon to the aimed child is hell!!!
Please!

@KutnerUri
Copy link
Contributor

I will check.

Why not import the svg as a regular react component?
I did it here like so:

// CurvePeek.tsx:
export function CurvePeek() {
  return (
    <svg
      viewBox="0 0 100 100"
      preserveAspectRatio="none"
      className="curvePeek"
    >
      <path d="M 0,100 Q 50,-100 100,100" />
    </svg>
  );
}

@KutnerUri
Copy link
Contributor

looking into it, it seems to be a problem with Webpack 5 compatibility:
gregberge/svgr#551

We seem to had supported it using a babel plugin, like so:
(but it no longer works because we don't apply babel on plugins, I guess)

plugins: [
  [
    require.resolve('babel-plugin-named-asset-import'),
    {
      loaderMap: {
        svg: {
          ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]',
        },
      },
    },
  ],
],

The way I see it, there are two easy options:

  1. using type: 'asset' to make it an inlineUrl:
{
  test: /\.svg$/,
  type: 'asset',
}
  1. using svgr to make it a react component:
{
  test: /\.svg$/,
  use: ['@svgr/webpack']
]

Combining the two generates an inline url from the react component, which accomplishes nothing.

I'm trying to use new-url-loader that supposed to accomplish both.

@KutnerUri
Copy link
Contributor

I made #4595. I tested it and it works locally.
What do you think? @dimo-ivanov @GiladShoham

@dimo-ivanov
Copy link
Author

dimo-ivanov commented Jul 28, 2021

Hi,
It works now when rendering/viewing the component in the collection after bit start, but when imported in a create-react-app this error appears: Error: 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.
React version: ^17.0.2

@KutnerUri
Copy link
Contributor

@dimo-ivanov - maybe the CRA has a different config for svgr?
can you send me a link to your component?

@MikaelColliander
Copy link

I'm having this issue too, Icons work on bit.dev but not in CRA. How was this resolved?

@burakgavaskargo
Copy link

I am having the same issue as @dimo-ivanov

@KutnerUri
Copy link
Contributor

KutnerUri commented May 25, 2022

works for me, please try importing this sample component:

bit import kutnerjs.exp/ui/assets-test

Screen Shot 2022-05-25 at 18 10 05

@willrbc
Copy link

willrbc commented Jun 21, 2022

This example component failed for me with the same error.

@benjgil
Copy link
Contributor

benjgil commented Jun 22, 2022

You can resolve this by adding a webpack config in your CRA app for loading svg files. Bit's UI uses @svgr/webpack, but there are numerous loaders available depending on your requirements. The same is true for any application build, for instance nextJs requires adding config to get this working too.

This isn't a bit issue, so I'm not sure what else we can help with I'm afraid

@MikaelColliander
Copy link

I had a similar issue - moving a component library from an integrated package, bundled with Rollup. I found it confusing that icons worked well locally and on bit.cloud but not when consumed in a Create React App. That was until I realized icons had previously been compiled with svgr/rollup. As I wanted the icons to be consumable by any React application I decided to have them precompiled and generated with svgr-cli before exporting them to bit.cloud.

I experienced these problems with CRA4. CRA5 should be able to render svgr as it stands. Hope this helps.

@KutnerUri
Copy link
Contributor

svgr is non standard and needs to be included in your bundler :)

This is why I'm not keen on adding non canonical things to bit.

@petatemarvin26
Copy link

petatemarvin26 commented Jul 1, 2023

Hi there!, @svgr/webpack provides ReactComponent named export, of course webpack doesn't know what is .svg so you need to explicity the file-loader as well, here is the best config for that and don't forget the definition module

{
  test: /\.(svg)$/,
  use: ['@svgr/webpack', 'file-loader']
}

check this out for your reference, petatemarvin26/vin-react

@benjgil
Copy link
Contributor

benjgil commented Jul 2, 2023

Hi All,
This is an old thread and the information here is outdated.
Bit's core react env, and custom envs which inherit from it, come with @svgr/webpack configured as standard, so there's no need to add any other config. I"m closing this as this is no longer an issue (and hasn't been for a while)

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

Successfully merging a pull request may close this issue.

9 participants