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

InvalidCharacterError: String contains an invalid character

Open Beetix opened this issue 4 years ago • 10 comments

Hi,

Running a project with Expo, I am getting an InvalidCharacterError: String contains an invalid character error on the web rendering. Android works fine and I haven't tested iOS.

I have the following dependencies in my package.json:

{
  ...
  "dependencies": {
    "expo": "~37.0.3",
    "react": "~16.9.0",
    "react-dom": "~16.9.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
    "react-native-svg": "11.0.1",
    "react-native-web": "~0.11.7"
  },
  "devDependencies": {
    "@babel/core": "^7.8.6",
    "babel-preset-expo": "~8.1.0",
    "react-native-svg-transformer": "^0.14.3"
  }
}

Here is my App.js, the Bower SVG was taken from react-native-svg-example:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import Bower from './assets/bower.svg';

export default function App() {
  return (
    <View style={styles.container}>
      <Bower width={256} height={256} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Does anyone have an idea of what's going on?

Thanks

Beetix avatar May 26 '20 13:05 Beetix

I have a similar error also on the web rendering

image

leup avatar May 29 '20 23:05 leup

I'm getting the exact same behaviour, but with vanilla react-native/react-native-web. Works perfectly fine on iOS and Android, but not web. SVG file generated (e.g. /static/media/user.a61f6f35.svg from above screenshot) exists and renders fine in Chrome.

gigaSproule avatar Jun 02 '20 11:06 gigaSproule

I'm getting the exact same behaviour, but with vanilla react-native/react-native-web. Works perfectly fine on iOS and Android, but not web. SVG file generated (e.g. /static/media/user.a61f6f35.svg from above screenshot) exists and renders fine in Chrome.

Ok, so the problem is not related to Expo. Good to know, thanks!

Beetix avatar Jun 02 '20 11:06 Beetix

I found a work around/fix. My file structure is:

/src
- /assets
-- /icons
--- /all-my-svg-files.svg
...

What I did was create 2 files, icons.ts and icons.web.ts under src/assets/icons. In icons.ts I had a list of entries such as import CloseSvg from "./close.svg"; export const Close = CloseSvg; and in icons.web.ts I had entries such as export { ReactComponent as Close } from "./close.svg";.

Only issue now is that I obviously can't share the style across both.

gigaSproule avatar Jun 02 '20 12:06 gigaSproule

Hmm.. I'm guessing that Expo is using a different way of exporting/importing SVG images for their Web rendering.

kristerkari avatar Jun 23 '20 06:06 kristerkari

Hmm.. I'm guessing that Expo is using a different way of exporting/importing SVG images for their Web rendering.

I don't think it is a problem related with Expo since @gigaSproule had the same problem with "vanilla react-native/react-native-web".

I saw made an example using Expo. I tried running it myself but I am getting the following error on web compilation.

/home/beetix/Tech/External/react-native-svg-expo-example/node_modules/react-native/Libraries/StyleSheet/processColor.js
Module not found: Can't resolve '../Utilities/Platform' in '/home/beetix/Tech/External/react-native-svg-expo-example/node_modules/react-native/Libraries/StyleSheet'

Do you remember if the web was rendering ok?

Beetix avatar Jun 23 '20 18:06 Beetix

Yes, to clarify, I am not using expo.

gigaSproule avatar Jun 30 '20 19:06 gigaSproule

@Beetix did you found a solution or some kind of workaround? Have the same problem

pascalhuszar avatar Nov 07 '20 13:11 pascalhuszar

This transformer only seems to be used for Android and iOS.

For Web, I found that I needed the following webpack.config.js:

const createExpoWebpackConfigAsync = require("@expo/webpack-config");
const { createAllLoaders } = require("@expo/webpack-config/loaders");

// Expo CLI will await this method so you can optionally return a promise.
module.exports = async (env, argv) => {
  const config = await createExpoWebpackConfigAsync(env, argv);

  config.module.rules = [
    // Enable svgr in web build.
    {
      oneOf: [
        {
          test: /\.svg$/,
          exclude: /node_modules/,
          use: [
            {
              loader: "@svgr/webpack",
            },
          ],
        },
      ].concat(createAllLoaders(env)),
    },
  ];

  // Finally return the new config for the CLI to use.
  return config;
};

For completeness, this is what I added to package.json:

{
  "dependencies": {
    "react-native-svg": "^12.1.0"
  },
  "devDependencies": {
    "@expo/webpack-config": "^0.12.40",
    "@svgr/webpack": "^5.4.0",
    "react-native-svg-transformer": "^0.14.3",
 }
}

and for Android into metro.config.js:

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"],
    },
  };
})();

I also have added the following to app.json but have no idea if it is necessary:

{
  "expo": {
   "packagerOpts": {
      "config": "metro.config.js",
      "sourceExts": [
        "expo.ts",
        "expo.tsx",
        "expo.js",
        "expo.jsx",
        "ts",
        "tsx",
        "js",
        "jsx",
        "json",
        "wasm",
        "svg"
      ]
    }
  }
}

jtojnar avatar Nov 07 '20 13:11 jtojnar

For those using Expo, I suspect this is related to

https://github.com/expo/expo-cli/blob/164b4d5b193c8351cb11ccec3fe6f732478caa23/packages/webpack-config/src/loaders/createAllLoaders.ts#L42-L51

(there is even a todo for handling SVG better.)

It appears to me that, depending on how you implement the rule for @spgr/webpack, ordering matters. You must unshift this rule to Expo's default set of oneOf rules so it comes before the rule linked, above.

bradjones1 avatar Feb 27 '23 07:02 bradjones1