create-react-app: Dynamic import doesn't work with SVG imported as ReactComponents
Is this a bug report?
Yes
Did you try recovering your dependencies?
Yes
Which terms did you search for in User Guide?
SVG, ReactComponent, dynamic import
Environment
System:
OS: macOS 10.14
CPU: x64 Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz
Binaries:
Node: 10.11.0 - /usr/local/bin/node
Yarn: 1.7.0 - /usr/local/bin/yarn
npm: 6.4.1 - /usr/local/bin/npm
Browsers:
Chrome: 69.0.3497.100
Firefox: 61.0.2
Safari: 12.0
npmPackages:
react: ^16.5.2 => 16.5.2
react-dom: ^16.5.2 => 16.5.2
react-scripts: 2.0.3 => 2.0.3
npmGlobalPackages:
create-react-app: 2.0.2
Steps to Reproduce
- Try to import SVG as ReactComponet using import(). Example code below
Expected Behavior
SVG loads
Actual Behavior
Got following error in browser
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.
This happens because importing module doesn’t contain ReactComponent property. Here’s console.log output from demo
Module {default: "/static/media/logo.5d5d9eef.svg", __esModule: true, Symbol(Symbol.toStringTag): "Module"}
Reproducible Demo
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor (props) {
super(props)
this.logoComponent = 'div'
}
componentDidMount () {
import('./logo.svg').then((m) => {
console.log(m)
this.logoComponent = m.ReactComponent
this.forceUpdate()
})
}
render() {
const Logo = this.logoComponent
return (
<div>
<Logo />
</div>
)
}
}
export default App;
Workaround
- Create file with following content
import { ReactComponent as Logo } from './logo.svg'
export default Logo
- Use dynamic import as usual for this file
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 37
- Comments: 27 (1 by maintainers)
Links to this issue
Commits related to this issue
- workaround from https://github.com/facebook/create-react-app/issues/5276 — committed to neolefty/indirect-svg by neolefty 4 years ago
- Move the old React app into the new Rails one This commit includes many changes: - The React components have been moved into `app/javascript/components` - For this, the relevant NPM modules (`style... — committed to AlbertoPdRF/whats-going-on by AlbertoPdRF 3 years ago
This fix only works in the Webpack-world
This seems to be caused by the fact that the Webpack plugin that adds the
ReactComponent
to each SVG that is imported somehow does not trigger on dynamic imports.In the webpack config of CRA, you can see the configuration for this:
As you can see, the
@svgr/webpack
loader is used to generate theReactComponent
and this loader is prepended to the filepath you specified for the svg.This means enforcing the same loader on your dynamic SVG import should fix your issues. The only difference is that the
ReactComponent
is now thedefault
output.With the update to 5.0.0 to CRA,
!!@svgr/webpack?-svgo,+titleProp,+ref![svg_file_path]
is not part of the config anymore, and isn’t being resolved with the@svgr/webpack?-svgo,+titleProp,+ref!
. I’m not seeing ReactComponent with default when importing dynamically likeimport(`${name}.svg)
. Are there any clues on how to go about doing this now?I am struggling with dynamically importing icons as well 😦, and I tried several approaches:
@svgr/webpack
and I get this error (I am not working in a new application but trying to refactor an existing one which hasfontawesome-free
package):By the way maybe this solution is with less configuration - https://stackoverflow.com/questions/55175445/cant-import-svg-into-next-js/70961634#70961634
I am getting nothing.
ImportedIconRef.current
is undefinedI am getting this error:
I am trying to avoid ejecting like @mattpodolak
I too have this issue and would like to know a solution!
can anyone explain to me why it works in codesandbox and not locally, with the EXACT same dependencies and versions?
https://codesandbox.io/s/blissful-cdn-9v8uk?file=/src/Icon.js
@DaftPaul I ended up ejecting and editing the webpack config as suggested here https://github.com/webpack/webpack/discussions/15117#discussioncomment-1925385
Came across this issue as well, and funnily enough I came across the same sandbox/dev.to post @kevinblilly and can’t understand why that sandbox works. My only guess is that even though “react-scripts” are defined in package.json, the webpack.config used by it is being overwritten by a default one from codesandbox. Following the thread it seems it’s not an easy issue to fix https://github.com/webpack/webpack/pull/10362
My solution to this was modifying the webpack.config with the package
react-app-rewired
. I don’t like it, at all, but solved the problem.Steps to use
react-app-rewired
:npm install react-app-rewired --save-dev
package.json
to contain :config-overrides.js
with content:This essentially maintains the current webpack.config but overwrites the section relating to
@svgr/webpack
to not have theissuer
attribute which seems to break ContextModule behavior. Be mindful this change might have side effects, please check https://github.com/webpack/webpack/pull/10362Having the same issue. It seems to work here: https://codesandbox.io/s/react-dynamic-svg-import-448dn?file=/src/App.js:777-791
So it might just be the babel/webpack configuration that’s messing things up.
We’re using
react-app-rewired
in combination with thecustomize-cra
package.LuisCor’s solution worked without ejecting but with the
customize-cra
package:Expanding on this solution, which works.
If you are using aliases in your create-react-app use the following.
For now I’ve mocked SVGs…
And in package.json
Another workaround is to use https://github.com/tanem/react-svg