-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Improve react-native-svg for the web using @svgr/webpack #6660
Comments
This is related issues :
|
The example in the docs can be run on web without an error, so this is most likely something specific to your code. If you can share a snack that reproduces this, that might help Closing this since it doesn't look to be a bug with the Expo SDK |
Hi @kopax Example on the link does work but they are not even a cents of the desired configured effect. It can work with react component on the web and so far, react-native-svg allows it. Their maintainers also reported that this is expo issue. I had no issue in the past to work with This must be configured and should be treated as a bug. I am still investigating on it. It seems that the 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
A sample project correctly configured with svgr that work for native and web (it use So far we have to rewrite the whole svg in another format. Do you mind reopening it? I will forward that question on the forum, but please consider taking it as a bug. I shouldn't have to write two components such as:
import React from 'react';
import Logo from './logo.svg';
export default (props) => <Logo accessibilityLabel="Logo" width="76" height="39" {...props} />;
import React from 'react';
import logo from './logo.svg';
export default (props) => <img alt="logo" width="76" height="39" src={logo} {...props} />; They are much different (on the web we won't have svg in the html, just an img pointing at the svg file so there's the whole scripted animation that cannot be done at this point). It work in native and does not on the web while it can. |
Yes, it is possible as described here
I have already tried and it does not work at all. (see comment here) Basically, this is how my 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 @cruzach it would help the investigation and improve expo if an expo maintainer, which is responsible for the logic used by expo webpack config to provide the final configuration to webpack, would give a hint on why the webpack config is behaving differently in expo context. |
@EvanBacon is probably most familiar with Expo when it comes to webpack & web, so he may have more insight, but when it comes to github issues it really helps if you are as clear and concise as possible. A title saying react-native-svg does not work at all on web is misleading, since it does work (see the example in our docs). You've also opened an issue on the same topic on multiple repos, so it's not clear exactly where you've determined the problem must lie |
Yes, I was trying to solve the issue for expo users and get proper advice from people that actually work on those libs. Unfortunately, they all redirected me to expo maintainers. They were quite surprised too that it wasn't possible to configure it using the I am willing to help, but I need some insight. What is webpack doing with |
Hi all, I ran into the same issue as @kopax and I think I have a fix. This seems to be a legitimate issue when using the default webpack config for Expo Web and importing SVGs from a separate file (which is why the official Expo demo works as well as the react-native-svg-example, which creates its own webpack config from scratch). The default Expo webpack config contains this rule which transforms SVGs with My SolutionTo prevent the upstream image loader from overriding // webpack.config.js
const createExpoWebpackConfigAsync = require('@expo/webpack-config');
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
// Remove existing rules about SVG and inject our own
// (Inspired by https://github.com/storybookjs/storybook/issues/6758#issuecomment-495598635)
config.module.rules = config.module.rules.map(rule => {
if (rule.oneOf) {
let hasModified = false;
const newRule = {
...rule,
oneOf: rule.oneOf.map(oneOfRule => {
if (oneOfRule.test && oneOfRule.test.toString().includes('svg')) {
hasModified = true;
const test = oneOfRule.test.toString().replace('|svg', '');
return { ...oneOfRule, test: new RegExp(test) };
} else {
return oneOfRule;
}
})
};
// Add new rule to use svgr
// Place at the beginning so that the default loader doesn't catch it
if (hasModified) {
newRule.oneOf.unshift({
test: /\.svg$/,
exclude: /node_modules/,
use: [
{
loader: '@svgr/webpack',
}
]
});
}
return newRule;
} else {
return rule;
}
});
return config;
}; Here is my // metro.config.js
const { getDefaultConfig } = require('metro-config');
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig();
return {
transformer: {
// This was important for me
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false
}
}),
babelTransformerPath: require.resolve('react-native-svg-transformer')
},
resolver: {
assetExts: assetExts.filter(ext => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg']
}
};
})(); Finally, remember to add the correct properties in your {
"expo": {
"packagerOpts": {
"config": "metro.config.js",
"sourceExts": ["js", "jsx", "ts", "tsx", "svg"]
}
}
} Hope this helps! |
Thanks a lot for sharing this configuration. I've just tested it, and it seems that it works like a charm. @cruzach perhaps bring this up to expo devs team? Another optimization would be to import by default as a This way, the user can decide whether he wants to have a simple URL or a React Component. ex: import url, { ReactComponent } from './myfile.svg'; |
@michaelgira23 Thank you so much for this solution. It was exactly what I needed as well to get SVGs to render properly using expo for all three platforms. |
@michaelgira23 thank you so much. |
I've had issues to put this solution in place, but somehow it's finally taken it. I'm unable however to restore the |
Hi @walidvb! I'm sorry I haven't worked with SVGs on Expo recently, so I don't know if anything has changed. For modifying any rule involving SVGs, you can modify this portion of the above solution: newRule.oneOf.unshift({
test: /\.svg$/,
exclude: /node_modules/,
use: [
{
loader: '@svgr/webpack',
}
]
}); The rest of the logic in my solution just gets the default Expo config that would otherwise normally be used, then injects this custom rule in place of the default SVG rule. The content passed into Looking at the issues you linked, you could try something like: newRule.oneOf.unshift({
test: /\.svg$/,
exclude: /node_modules/,
use: [{
loader: '@svgr/webpack',
options: {
svgoConfig: {
plugins: {
removeViewBox: false
}
}
}
}, 'file-loader']
}); |
Thanks @michaelgira23 I'm not sure exactly what changes I had to make, as it seemed to suddenly start working 🤔 For those needed this, here is my complete config:
and relevant modules:
|
@michaelgira23 just want to say thank you for diving deep to figure this out - the rule.oneOf replacement solved my problem perfectly! |
If anyone is looking for a config to simply copy-paste, you are welcome :) const createExpoWebpackConfigAsync = require('@expo/webpack-config');
/**
* @see https://github.com/expo/expo/issues/6660#issuecomment-667991626
* @see https://github.com/kristerkari/react-native-svg-transformer/issues/135#issuecomment-1008310514
*/
const withSVGR = config => {
config.module.rules = config.module.rules.map(rule => {
if (rule.oneOf) {
rule.oneOf.unshift({
test: /.svg$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('@svgr/webpack'),
options: {
expandProps: 'end',
native: true,
},
},
],
});
}
return rule;
});
return config;
};
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
// Customize the config before returning it.
return withSVGR(config);
}; |
@ElForastero I'm having a compile error with your solution.. Versions I'm using:
Do you know what's going on? |
@Estevete Try to check your Webpack version. Latest SVGR works only with Webpack V5. Maybe that's the case 🤔 |
@ElForastero I didn't have weback installed on my project. I was using the one from Expo. I've tried to npm install it with version 5.70.0 and when building web I get an error of metro-hermes.
Do you know anything about it? |
Same issue here as Estevete, does not seem to work with latest Expo, webpack, react-native-svg, react-native-svg-transformer and svgr/webpack. Got
Can't get svg to work on web with this config. Without it I get the PascalCase error kopax got. I did manage to get it working on web by adding the babel-plugin-inline-react-svg. But then I got: Invariant Violation: View config getter callback for component 'path' bla bla blah, must begin with upper case and so on on Android. Though not for all files, I had a brief moment of happiness with that config where almost every SVG worked, but after clearing cache ( A workaround has been to use Edit; By searching Github I found a solution. https://github.com/HolovisSoftwareDev/react-native-svg-transformer-fix-expo
Can confirm it works that way with the following config: webpack.config.js:
metro.config.js:
Now I can use SVGs in web, iOS and Android with the following code:
This is on an Expo project with bare workflow with these dependencies: react-native-svg So the solution to get it working on Expo is there right in that repo. Hopefully someone can fix it, but not sure if this should be fixed in Expo or in react-native-svg-transformer? When that is done one could get rid of the fix dependency. |
To anyone still having that issue. Just downgrade your @svgr/webpack to v5 gregberge/svgr#665 (comment) |
Dear future readers, as of today using Expo 48.0.6, react-native-svg 13.4.0, and @svgr/webpack 6.5.1, ElForastero's code works perfectly, no need to downgrade webpack anymore! |
@michaelgira23 @ElForastero thank you so much for this. I've been banging my head against the wall for days. |
Documentation: https://docs.expo.io/versions/latest/sdk/svg/
I have installed in my project
expo install react-native-svg
.I have exported the svg as a component by doing:
It can render on native but fail on the web.
I have followed that configuration https://github.com/react-native-community/react-native-svg#use-with-svg-files
My
metro.config.js
is equal:My
app.json
got addedThe text was updated successfully, but these errors were encountered: