Skip to content
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

Dynamically import svgs #51

Open
mick-feller opened this issue Oct 4, 2018 · 7 comments
Open

Dynamically import svgs #51

mick-feller opened this issue Oct 4, 2018 · 7 comments

Comments

@mick-feller
Copy link

mick-feller commented Oct 4, 2018

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?

@chaance
Copy link

chaance commented Dec 19, 2018

@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 */)
})

@yairEO
Copy link

yairEO commented Jun 18, 2019

@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"}

@yairEO
Copy link

yairEO commented Jun 19, 2019

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.

@yairEO
Copy link

yairEO commented Jun 19, 2019

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

@AwsmOli
Copy link

AwsmOli commented Jul 18, 2019

This will give you require.context for rollup: https://www.npmjs.com/package/rollup-plugin-require-context

@jp1987
Copy link

jp1987 commented May 20, 2022

@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

@mick-feller
Copy link
Author

@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;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants