react-native-svg-transformer icon indicating copy to clipboard operation
react-native-svg-transformer copied to clipboard

work on the web, Warning: </static/media/splashScreen.0f923900.svg /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.

Open kopax opened this issue 5 years ago • 12 comments
trafficstars

I have installed in my project expo install react-native-svg.

I have exported the svg as a component by doing:

import Logo from './logo.svg';
export default Logo;

It can render on native but fail on the web.

bundle.js:69367 Warning: </static/media/splashScreen.0f923900.svg /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.

I have followed that configuration https://github.com/react-native-community/react-native-svg#use-with-svg-files

My metro.config.js is equal:

const { getDefaultConfig } = require('metro-config');

module.exports = (async () => {
  const {
    resolver: { sourceExts, assetExts },
  } = await getDefaultConfig();
  return {
    transformer: {
      babelTransformerPath: require.resolve('react-native-svg-transformer'),
    },
    resolver: {
      assetExts: assetExts.filter(ext => ext !== 'svg'),
      sourceExts: [...sourceExts, 'svg'],
    },
  };
})();

My app.json got added

{
+    "packagerOpts": {
+      "config": "metro.config.js",
+      "sourceExts": ["js", "jsx", "ts", "tsx", "svg"]
+    },
}
  • react-native-svg 9.13.3
  • react-native-svg-transformer 0.14.3
  • SDK: 36 Documentation: https://docs.expo.io/versions/latest/sdk/svg/

kopax avatar Jan 03 '20 03:01 kopax

This is quite blocking for doing web.

I have prepared a reproduction and I have found inconsistency with another project that is configured the same way:

svg/test.svg:

  <svg height="100%" width="100%">
    <rect fill="lime" width="100%" height="100%" />
  </svg>

svg/index.js

import Svg from 'test.svg';
console.log(Svg)
export default Svg;

There are two issues:

  1. web: console.log(Svg) does not return a component (it return for example data:image/svg+xml;base64,ICA8c3ZnIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiPgogICAgPHJlY3QgZmlsbD0ibGltZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgLz4KICA8L3N2Zz4=)
  2. test: jest unit testing does not return a component (instead an integer and test always have Platform.OS === 'ios' (why?))

While in the original project I was creating the issue for:

  1. web: console.log(Svg) does not return a component (it return for example /static/media/logo.0e5dcfee.svg)
  2. jest: unit testing does return a component (and Platform.OS === 'ios')

Both work fine on iOS and Android.

I know from the past that @svgr and @svgr/webpack work perfectly for the web (normally with import { ReactComponent } from './test.svg';

kopax avatar Jan 03 '20 03:01 kopax

Hi @kopax! I currently have no idea of how the Web side works in Expo. I think that I need to sit down and have a look at it.

There is an example app with Native + Web support, which does not use Expo, but uses Webpack + SVGR instead: https://github.com/kristerkari/react-native-svg-example

kristerkari avatar Jan 03 '20 09:01 kristerkari

Thanks @kristerkari for your reply. I will post the expo webpack configuration of expo. I think this is due to this probably missing, I will let you know

https://github.com/kristerkari/react-native-svg-example/blob/master/webpack.config.js#L33

kopax avatar Jan 03 '20 14:01 kopax

I just add a whole session around your example and the svgr documentation.

After multiple attempl, including a copy past of your webpack config, I still have a path when requiring an svg.

I have re-asked my question here : https://github.com/gregberge/svgr/issues/375

And opened an issue on expo here: https://github.com/expo/expo/issues/6660

But they closed it, so far nobody from any of the core libs want to dig into it at the moment.

Note that I have pasted in here the whole webpack configuration used by expo, and they had by default nothing configured between webpack and svgr.

kopax avatar Jan 03 '20 17:01 kopax

Is it possible for the user of Expo to extend Expo's Webpack config? That way you could add the @svgr/webpack dependency and configure it.

kristerkari avatar Jan 03 '20 19:01 kristerkari

Is it possible for the user of Expo to extend Expo's Webpack config?

Yes, it is possible as described here

That way you could add the @svgr/webpack dependency and configure it.

I have already tried and it does not work at all. (see comment here)

Basically, this is how my webpack.config.js looks like : https://github.com/kopax/expo-bug-reports/blob/issue-6660/webpack.config.js

The whole reproduction (which is an expo blank project, nothing more) can be run:

git clone https://github.com/kopax/expo-bug-reports.git
cd expo-bug-reports
git checkout issue-6660
npm i 
npm test
npm run web

image

Without the webpack.config.js, at least we can use the require return in <img />, while with @svgr/webpack, we can't (error remains the same)

kopax avatar Jan 03 '20 20:01 kopax

Hello! I ran into the same issue while using the default Expo webpack config for web. You indeed have to extend the default config, but also modify some existing rules that would otherwise override @svgr/webpack. I posted a fix here: https://github.com/expo/expo/issues/6660#issuecomment-573506912

michaelgira23 avatar Jan 13 '20 20:01 michaelgira23

Thanks for looking into it @michaelgira23! Let's see if we manage to get some fix for the documentation to Expo or this repo, so that in the future it will be easier to use the same code for both Web and Native.

kristerkari avatar Jan 13 '20 20:01 kristerkari

I have tested @michaelgira23 fix and it does work. To be near perfection, we should be able to decide if we import the url or the react component, usually with import svg, { ReactComponent } from './mysvg.svg';. This is already possible with svgr, and should be configured for native and webpack.

Yes this should definitely be included in the expo core configuration.

kopax avatar Jan 14 '20 09:01 kopax

I'm doing this for now to make it work,

const Icon = ({ children }) => {
  if (Platform.OS === 'web') {
    return <img src={children.type} {...children.props} />;
  }
  return children;
};

 <Icon>
     <ArrowBackIcon width={32} height={32} />
</Icon>

pyrossh avatar May 24 '20 12:05 pyrossh

Would just mention my comment here: https://github.com/expo/expo/issues/6660#issuecomment-1076338873

There is someone who has fixed this issue in this unpublished package: https://github.com/HolovisSoftwareDev/react-native-svg-transformer-fix-expo

See my comment for an example.

I can confirm it then works with latest Expo, react-native-svg and react-native-svg-transfomer on web, iOS and Android without the need to run Platform.OS checks when importing static svg files.

It is however not clear to me if this issue fix has to be implemented on the Expo side or in react-native-svg-transformer, but maybe you could take a look when you have time @kristerkari . This issue has been a huge pain for me, used several days troubleshooting, finally found a solution that works. But it would be nice to get rid of the unpublished fix package and just use react-native-svg and react-native-svg-transformer when using Expo, but the bug has to be fixed first.

joranb avatar Mar 23 '22 20:03 joranb

Here's how I'm configured to do React Native plus React Native Web .svg file loading, using the react-native-svg-transformer and @svgr/webpack packages allowing for same import / use on both mobile and web. The SVGs are also resizable and can have their fill color changed (if you do no fill in the .svg)

metro.config.js

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */

const { getDefaultConfig } = require('metro-config');

module.exports = async () => {
  const {
    resolver: { sourceExts, assetExts },
  } = await getDefaultConfig();

  return {
    transformer: {
      babelTransformerPath: require.resolve('react-native-svg-transformer'),
      getTransformOptions: async () => ({
        transform: {
          experimentalImportSupport: false,
          inlineRequires: false,
        },
      }),
    },
    resolver: {
      assetExts: assetExts.filter(ext => ext !== 'svg'),
      sourceExts: [...sourceExts, 'svg'],
    },
  };
};

webpack.config.js (excerpt)

...
const svgLoaderConfiguration = {
  test: /\.svg$/i,
  issuer: /\.[jt]sx?$/,
  use: [{ loader: '@svgr/webpack', options: { typescript: true, dimensions: false } }],
};
...

Example use

import AppLogo from './assets/AppLogo.svg';
...
<AppLogo fill={'green'} width={100} height={100} />

jkoutavas avatar Nov 19 '22 01:11 jkoutavas