I have some library, written by me. It has Icon
component which dynamically imports .svg. I have also client (react application written with create-react-app) which uses this library. In short, when I import Icon
component and use it it throws an error that resource was not found.
Longer story after debugging. My .svgs are bundled each to different directory, like:
dist/
4132/ // some icon ID
index.js // index.js with module which returns svg string
index.js // my Icon component bundled
and client app tries to load it from /static/4132/index.js but there is no /static/
folder in my client app with this directory. When I move 4132 directory to /public/static
everything works fine but it should not be like that. Icon component should fetch .svg from node_modules/my-library/dist/4132/index.js
My-library webpack config:
const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: "production",
entry: {
assets: ["./assets/src/icons/index.ts", "/assets/src/animations/index.ts"],
components: "./components/src/index.external.ts",
},
module: {
rules: [
{
test: /.inline.svg$/,
loader: "svg-inline-loader",
options: {
removeTags: true,
removingTags: ["title"],
classPrefix: true,
idPrefix: true,
},
},
{
test: /.(j|t)sx?$/,
use: [
{
loader: "babel-loader?cacheDirectory=true",
options: {
rootMode: "upward",
},
},
],
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
alias: {
"@ds/assets/animations": path.resolve(__dirname, "assets/src/animations"),
"@ds/assets/icons": path.resolve(__dirname, "assets/src/icons")
},
},
output: {
filename: "[name]/index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "umd",
},
externals: {
react: "react",
"react-dom": "react-dom",
},
};
My Icon.tsx component
import React, { forwardRef, memo, useLayoutEffect, useState } from "react";
// ...
export type IconProps = Pick<BoxProps, "width" | "height"> & {
alt?: string;
fill?: ColorToken;
inverted?: boolean;
name: IconName;
};
const defaultSize = "inherit";
export const iconNames = Object.keys(icons);
export const Icon = memo(
forwardRef<HTMLDivElement, IconProps>(
({ alt, fill, height = defaultSize, inverted = false, name, width = defaultSize }, ref) => {
const [icon, setIcon] = useState("");
const { colors } = useTheme();
const id = useId();
useLayoutEffect(() => {
let unmounted = false;
const fetchIcon = async () => {
const data = await import(`@ds/assets/icons/${name}.inline.svg`);
if (!unmounted) {
setIcon(data.default?.replace(/(id=")(.*?)(")/gm, `$1${id}$3`));
}
};
fetchIcon();
return () => {
unmounted = true;
};
}, [id, name]);
return (
<Box
aria-hidden={!alt}
aria-label={alt}
dangerouslySetInnerHTML={{ __html: icon ?? "" }}
height={height}
ref={ref}
role={alt ? undefined : "img"}
width={width}
/>
);
},
),
);