Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use Vite's glob import to dynamically generate React components?

I'm creating a component library, and I wish to add SVG icons as individual components to be consumed by other apps. I'm using vite-plugin-svgr to generate components from icons, and it seems like it's building them successfully, but it's not doing so at build time, it's doing it in the browser.

I'm trying to build up an object to export all of the icons from a folder.

const svgs: any = import.meta.glob('./assets/icons/*.svg', { eager: true });

const iconComponents: any = {};

for (const path in svgs) {
  const component = svgs[path].ReactComponent;
  const name: string = component.name.replace(/^Svg/, '') + 'Icon';
  iconComponents[name] = component;
}

export default iconComponents;

The iteration and export works in that I can just put the SVGs in a folder, then I can view them in storybook. But when I go to actually build the component library, none of the icons are exported. It seems as though this glob import is actually executed by Vite at runtime somehow, but not on build.

Is there a good way to dynamically generate these components so that I can just put SVGs in a folder and have the components be generated?

Here's my vite config for reference:

import react from '@vitejs/plugin-react';
import { resolve } from 'path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import tsConfigPaths from 'vite-tsconfig-paths';
import * as packageJson from './package.json';
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
import svgr from 'vite-plugin-svgr';

export default defineConfig(() => ({
  plugins: [
    cssInjectedByJsPlugin(),
    svgr({
      include: '**/*.svg'
    }),
    react(),
    tsConfigPaths() as any,
    dts({
      include: ['src'],
    }),
  ],
  build: {
    lib: {
      entry: resolve('src', 'index.ts'),
      name: 'red-mist',
      formats: ['es', 'cjs'],
      fileName: (format) => `my-lib.${format}.js`,
    },
    rollupOptions: {
      external: [...Object.keys(packageJson.peerDependencies)],
      input: {
        index: resolve('src', 'index.ts'),
        css: resolve('src', 'index.css'),
      },
    },
  },
}));
like image 312
counterbeing Avatar asked Dec 09 '25 08:12

counterbeing


1 Answers

For me, this did the job:

const icons = import.meta.glob('src/static/icons/*.svg', {
  query: '?react',
  eager: true,
});

In earlier versions of vite, it might also be as: 'react' instead of query.

Then I get back an object and the first value looks like this:

Object { default: SvgIconPathToFile(props), … }

This can be rendered as Jsx as usual.

like image 72
angelozehr Avatar answered Dec 11 '25 21:12

angelozehr