4

I'm using single-spa for modular React app. I'm using Typescript, Webpack and svg-url-loader. The SVG appears to be generated and present ([hash].svg), but is not loaded correctly (you cannot see the image, just a placeholder).

Here is my Webpack configuration:

module.exports = (webpackConfigEnv, argv) => {
  const defaultConfig = singleSpaDefaults({
    orgName: "Daboo1998",
    projectName: "react-module",
    webpackConfigEnv,
    argv,
  });

  return merge(defaultConfig, {
    // modify the webpack config however you'd like to by adding to this object
    module: {
      rules: [
        {
          test: /\.svg$/,
          use: [
            {
              loader: 'svg-url-loader',
              options: {
                limit: 10000000,
              },
            },
          ],
        },
      ]
    }
  });
};

Thats the SVG decleration:

declare module "*.svg" {
  const src: string;
  export default src;
}

and that how I use it:

import homeIcon from "./icons/house-4.svg";

...
<img src={homeIcon} />

What could I be doing wrong? If more information is needed, please comment!

3 Answers3

3

As its in svg (scalar vector graphic), so its an image by itself, dont need to go inside an src attribute, you can render homeIcon itself.

What i recommend you for this case is to create Homeicon as a component (homeIcon.tsx) as following (My example is with an EllipsisIcon):

import React from "react";

const EllipsisIcon = () => {
    return (
        <svg
            aria-hidden="true"
            focusable="false"
            data-prefix="fal"
            data-icon="ellipsis-v"
            className="svg-inline--fa fa-ellipsis-v fa-w-2"
            role="img"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 64 512"
        >
            <path
                fill="currentColor"
                d="M32 224c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zM0 136c0 17.7 14.3 32 32 32s32-14.3 32-32-14.3-32-32-32-32 14.3-32 32zm0 240c0 17.7 14.3 32 32 32s32-14.3 32-32-14.3-32-32-32-32 14.3-32 32z"
            ></path>
        </svg>
    );
};

export default EllipsisIcon;

And to implement It you import it as a normal component and use it in the return as usual. Import EllipsisIcon from “…” Using it as where you need

Nacho
  • 870
  • 6
  • 9
1

You can display SVGs using the img element with webpack file-loader, assuming you're using less than webpack 5. Do npm install file-loader --save-dev and add to the rules arrays in the webpack config

 {
    test: /\.(png|jpe?g|gif|svg)$/i,
    use: [
      {
        loader: 'file-loader',
      },
    ],
  },

It can be tricky styling SVG asset with the img element, so you're better of creating a react component to render the SVG for you as described by @Nacho

Niyi Aromokeye
  • 411
  • 5
  • 9
1

React normally supports svg and does not require webpack editing.

You can define Svg's in a folder in src

Ex: eye.svg


<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
    <path d="M15.75 12C15.75 12.9946 15.3549 13.9484 14.6517 14.6517C13.9484 15.3549 12.9946 15.75 12 15.75C11.0054 15.75 10.0516 15.3549 9.34835 14.6517C8.64509 13.9484 8.25 12.9946 8.25 12C8.25 11.0054 8.64509 10.0516 9.34835 9.34835C10.0516 8.64509 11.0054 8.25 12 8.25C12.9946 8.25 13.9484 8.64509 14.6517 9.34835C15.3549 10.0516 15.75 11.0054 15.75 12Z" />
    <path fill-rule="evenodd" clip-rule="evenodd" d="M0 12C0 12 4.5 3.75 12 3.75C19.5 3.75 24 12 24 12C24 12 19.5 20.25 12 20.25C4.5 20.25 0 12 0 12ZM12 17.25C13.3924 17.25 14.7277 16.6969 15.7123 15.7123C16.6969 14.7277 17.25 13.3924 17.25 12C17.25 10.6076 16.6969 9.27226 15.7123 8.28769C14.7277 7.30312 13.3924 6.75 12 6.75C10.6076 6.75 9.27226 7.30312 8.28769 8.28769C7.30312 9.27226 6.75 10.6076 6.75 12C6.75 13.3924 7.30312 14.7277 8.28769 15.7123C9.27226 16.6969 10.6076 17.25 12 17.25Z" />
</svg>
    

Notice: Use currentColor for changes

Use ReactComponents to use svg

import {ReactComponents as EyeSvg} from '...';

const Component = () => {
    return (
        <button
            style={{ color: "red" }}
        >
            <EyeSvg width="18" height="18" />
        </button>
    );
}

export default Component;

If you changed your webpack.config.js

            // "url" loader works like "file" loader except that it embeds assets
            // smaller than specified limit in bytes as data URLs to avoid requests.
            // A missing `test` is equivalent to a match.
            {
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
              loader: require.resolve('url-loader'),
              options: {
                limit: imageInlineSizeLimit,
                name: 'static/media/[name].[hash:8].[ext]',
              },
            },
            // Process application JS with Babel.
            // The preset includes JSX, Flow, TypeScript, and some ESnext features.
            {
              test: /\.(js|mjs|jsx|ts|tsx)$/,
              include: paths.appSrc,
              loader: require.resolve('babel-loader'),
              options: {
                customize: require.resolve(
                  'babel-preset-react-app/webpack-overrides'
                ),
                presets: [
                  [
                    require.resolve('babel-preset-react-app'),
                    {
                      runtime: hasJsxRuntime ? 'automatic' : 'classic',
                    },
                  ],
                ],
                
                plugins: [
                  [
                    require.resolve('babel-plugin-named-asset-import'),
                    {
                      loaderMap: {
                        svg: {
                          ReactComponent:
                            '@svgr/webpack?-svgo,+titleProp,+ref![path]',
                        },
                      },
                    },
                  ],
                  isEnvDevelopment &&
                    shouldUseReactRefresh &&
                    require.resolve('react-refresh/babel'),
                ].filter(Boolean),
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },
Ali Yaghoubi
  • 1,258
  • 8
  • 15