babel-plugin-inline-react-svg
babel-plugin-inline-react-svg copied to clipboard
Dynamically import svgs
So we have a library with all our svg icons in it.
I'm looking for a way to import all these svgs dynamically and display them in our styleguide (storybook) to give a visual representation of which icons we have.
I was trying something like this but no luck:
const reqSvgs = require.context('./svgdir', true, /\.svg$/);
reqSvgs.keys().map((filename) => {
return (
<div className="icon">
{reqSvgs(filename)}
</div>
);
})
But no luck, anyone any idea how i can make this work?
@mick-feller Have you tried the dynamic import syntax? https://reactjs.org/docs/code-splitting.html#import? This is untested, but I think it should look something like this:
const reqSvgs = require.context('./svgdir', true, /\.svg$/);
reqSvgs.keys().map((filename) => {
import(`./svgdir/${filename}`)
.then(Icon =>
<div key={filename} className="icon">
<Icon />
</div>
)
.catch(/* fallback */)
})
@chancestrickland - How would you use each specific Icon in JSX when implementing your method?
Doing import(`./svgdir/${filename}`)
gives:
Module {default: "static/media/spinner.aabcf541.svg", __esModule: true, Symbol(Symbol.toStringTag): "Module"}
This does not work:
let Foo;
// I've placed a single svg file in the folder
const reqSvgs = require.context('./icons', true, /\.svg$/);
reqSvgs.keys().map((filename) => {
filename = filename.replace('./','')
let name = filename.replace(/\.[^.]*$/,'')
import(`./icons/${filename}`)
.then(Icon => {
Foo = () => <Icon />;
})
})
const Icon = ({type}) => {
return <Foo/> // assume this will be dynamic using "type"
}
export default Icon
ERROR:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of
Foo
.
I now understand require.context
is a webpack-only thing and I do not want webpack in my code, since I don't have an app, just a single standalone <Icon>
component
This will give you require.context
for rollup: https://www.npmjs.com/package/rollup-plugin-require-context
@yairEO @mick-feller did you ever fix this?
I'm trying to import inline:
import(`../Icons/${name}.svg`).then(icon => {
console.log(icon);
})
Which returns the module.
Webpack config:
{
test: /\.svg$/,
use: ['babel-loader']
}
And running version 2.0.1
@jp1987 we actually moved away from this plugin and went with @svgr/webpack, the webpack piece is what we setup in storybook, but you can obviously convert this to regular webpack.
config.module.rules.push({
test: /\.svg?$/,
oneOf: [
{
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: true,
svgoConfig: {
removeViewBox: false
},
titleProp: true,
},
},
]
}
]
})
And then in our code we actually do this to generate an object of all our SVG's in a folder:
const getSVGS = () => {
const context = require.context('../../icons', true, /\.svg$/);
const obj = {};
context.keys().forEach((key) => {
obj[key] = context(key).default;
});
return obj;
};