javascript - Hvordan få SVG React-komponentimporter fra ekstern modul til å fungere med create-react-app?


Kontekst

For å gjøre noen kodebiter gjenbrukbare på tvers av mange React-prosjekter, har jeg følgende prosjektstruktur:

  1. @foo/design: Inneholder designelementer som rå SVG-bilder
  2. @foo/ui: Et React-bibliotek basert på Create React App for vanlige komponenter
  3. @foo/project: Et endelig CRA-prosjekt som bruker foo/ui

Biblioteket

Biblioteket foo/ui eksporterer en komponent som importerer et SVG-bilde fra @foo/design:

// MyComponent.ts
import React, { FC } from 'react';
import {
  ReactComponent as Logo,
} from '@foo/design/static/img/logo.svg';

export const MyComponent: FC = () => {
  return (
    <div>
      Some stuff.
      <Logo />
    </div>
  );
};

export default null;

Denne komponenten fungerer feilfritt på den relaterte Storybook-instansen av @foo/ui og blir kompilert ved hjelp av tsc på denne måten:

// MyComponent.js
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { ReactComponent as Logo, } from '@foo/design/static/img/logo.svg';
export var Navbar = function () {
    return (_jsxs("div", { children: ["Some stuff.", _jsx(Logo, {}, void 0)] }, void 0));
};
export default null;

Her er også den tilhørende tsconfig.json-filen:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "declaration": true,
    "outDir": "./lib",
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx"
  },
  "include": ["src"],
  "exclude": [
    "src/samples",
    "src/**/*.stories.*",
    "src/**/*.test.*",
    "src/setupTests.js"
  ],
}

Prosjektimporten

På @foo/project la jeg til @foo/ui-avhengigheten og installerte også @foo/design-pakken (påkrevd av @foo/ui).

Jeg bruker komponenten min på denne måten:

import { FC } from 'react';
import { MyComponent } from '@foo/ui'

const App: FC = () => {
  return (
    <MyComponent />
  );
}

export default App;

Men dette gir følgende feil:

Failed to compile.

./node_modules/@foo/ui/lib/MyComponent.js
Attempted import error: 'ReactComponent' is not exported from '@foo/design/static/img/logo.svg' (imported as 'Logo').

Men hvis jeg kopierer/limer inn svg-importlinjen fra MyComponent.js direkte i min rotnavngitte app-komponent:

import { FC } from 'react';
import { ReactComponent as Logo, } from '@foo/design/static/img/logo.svg';

const App: FC = () => {
  return (
    <Logo />
  );
}

export default App;

Dette fungerer, og SVG-en vises som forventet.

Her er også CRA-prosjektets relaterte tsconfig.json-fil:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

Hvorfor fungerer ikke ReactComponent CRA-importen når den gjøres fra mitt importerte bibliotek? Hva er den enkleste måten å løse dette problemet på siden @foo/ui kun brukes internt?

Takk

Svar #1

Jeg fant at den eneste løsningen som hjalp meg i en lignende situasjon, er å definere SVG-komponenten inline, ved å bruke https://svg2jsx.com/ for å forberede komponenten.

Så, i ditt tilfelle, vil du ikke kunne bruke delte SVG-er fra @foo/design for å lage en wrapper-komponent, men i det minste vil du kunne forberede de delte SVG-komponentene i @foo/ui.

Brukte mye tid, løste det nettopp, så kan ikke forklare hva det underliggende problemet er.

Relaterte artikler