Open vitalyiegorov opened 5 years ago
Not sure what library/plugin CRA is using for the SVG images, but the idea with this transformer is that you can use SVGR in you Web projects, and the images and properties will work 100% the same between Web and React Native.
Can SVGR easily be added to CRA? That would fix the problem for you.
The fix that you are suggesting is a breaking change, so I'm not that keen on making it if it can be avoided.
Why do you think that this is a breaking change? It would leave default export SvgComponent
and same usage import Logo from './logo.svg';
unchanged, but also it will give ability to use named export: import {ReactComponent as Logo} from './logo.svg';
which is supported by default by CRA.
CRA uses SVGR but with some modifications, I am just trying to enable the simple bridge to use this plugin with react-native-web and CRA.
Why do you think that this is a breaking change? It would leave
default export SvgComponent
and same usageimport Logo from './logo.svg';
unchanged
True, that would not be a breaking change, but the Typescript types will not be compatible with CRA as in CRA the default import seems to be a string, and the named import is a React component.
I need to look into the CRA docs a bit more to see if I'm looking at the correct things.
Actually, I'm not completely sure if the default import in CRA is the url or not, I tried to look at this, but I'm not sure: https://github.com/facebook/create-react-app/issues/3722
@kristerkari Referring to CRA docs, you could use default export for SVG usage as image source:
import Logo from './logo.svg';
...
return <image src={Logo}/>
or use SVG as react component:
import {ReactComponent as Logo} from './logo.svg';
...
return <Logo/>
Yes exactly, and that's the problem: it works differently from the changes that you are suggesting. Which means that the default import would return a component in React Native, but a url in Web.
Yes, but this transformer is not used in any CRA projects, they have their own configuration and transformer, its recommended to use this transformer only with React Native CLI projects, so this modification will influence only React Native projects which are using this transformer and thus adding named export won't break any existing React Native projects because the case with returning default as a string is not used in React Native projects, but this will give the ability to add react-native-web support to existing React Native CLI projects by changing default imports to named imports.
this modification will influence only React Native projects which are using this transformer and thus adding named export won't break any existing React Native projects because the case with returning default as a string is not used in React Native projects, but this will give the ability to add react-native-web support to existing React Native CLI projects by changing default imports to named imports.
I get that, but the change that you are suggesting also means that there would be types mismatch when sharing the same code between React Native and React Web with CRA and using Typescript or Flow.
I understand that many people are using CRA as their boilerplate, but what they do for Web doesn't make sense on the React Native side.
I use Typescript in most of my projects, and I'm not keen on making a change that only partially matches what CRA is doing, as all the existing users of this library are already using the default import for the React component.
I would suggest that you try to use @svgr/webpack
directly instead, like it's set up in the demo project:
https://github.com/kristerkari/react-native-svg-example/blob/master/webpack.config.js#L28-L38
@vitalyiegorov You can set a custom template for SVGR.
// svgr.config.js
const isExportNamedDeclaration = item => item.type === "ExportNamedDeclaration";
const hasExportNamedDeclaration = (items) => {
if (items === null) {
return false;
}
if (items instanceof Array) {
return !!(items && items.find(isExportNamedDeclaration))
}
return isExportNamedDeclaration(items)
}
const getName = (component) => {
if (component instanceof Object) {
return component.name;
}
return component;
}
const customTemplate = (
{ template },
opts,
{ imports, componentName, props, jsx, exports },
) => {
const ReactComponent = hasExportNamedDeclaration(exports)
? ''
: 'export const ReactComponent = ' + getName(componentName);
return template.ast`
${imports}
function ${componentName}(${props}) {
return ${jsx};
}
${ReactComponent}
${exports}
`
}
module.exports = {
template: customTemplate
}
@kristerkari Maybe it will be useful, so let's add it to the README file.
@vitalyiegorov You can set a custom template for SVGR.
// svgr.config.js const isExportNamedDeclaration = item => item.type === "ExportNamedDeclaration"; const hasExportNamedDeclaration = (items) => { if (items === null) { return false; } if (items instanceof Array) { return !!(items && items.find(isExportNamedDeclaration)) } return isExportNamedDeclaration(items) } const getName = (component) => { if (component instanceof Object) { return component.name; } return component; } const customTemplate = ( { template }, opts, { imports, componentName, props, jsx, exports }, ) => { const ReactComponent = hasExportNamedDeclaration(exports) ? '' : 'export const ReactComponent = ' + getName(componentName); return template.ast` ${imports} function ${componentName}(${props}) { return ${jsx}; } ${ReactComponent} ${exports} ` } module.exports = { template: customTemplate }
@kristerkari Maybe it will be useful, so let's add it to the README file.
Can you add this into the root of your project to handle the SVGs for web? Do you need to do anything else?
Since SVGR v6.0.0, switching to named exports is just a matter of adding exportType: 'named'
to your svgrrc file
Hi @kristerkari,
Thank you for your plugin it is working great for React native projects,
We are trying to share our codebase across react-native and web(using react-native-web), our codebase is originally developed for React native CLI project, now we would like to add web support and using CRA with CRA-rewired but we are facing a problem:
According to CRA docs if you want to import SVG as react component you should use:
import { ReactComponent as Logo } from './logo.svg';
but SVGR is making only
export default SvgComponent
so we cannot use this approach, to fix this we could add a small fix here which should not break anything:which gives us needed support to work in react-native and web projects(also definitions.d.ts should be updated accordingly).
Maybe we could make a PR for this, or what do you think?
Here is a quick fix for
postinstall
npm/yarn script: