{"_id":"@acusti/vite-plugin-svg-react","_rev":"4-c45c1378bf207e0522afdf44fdfbe4e4","name":"@acusti/vite-plugin-svg-react","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@acusti/vite-plugin-svg-react","version":"0.1.0","keywords":["oxc","react","rolldown","svg","svgr","ts","typescript","vite","vite-plugin"],"author":{"url":"https://www.acusti.ca","name":"andrew patton","email":"andrew@acusti.ca"},"license":"Unlicense","_id":"@acusti/vite-plugin-svg-react@0.1.0","maintainers":[{"name":"acusti","email":"andrew@acusti.ca"}],"homepage":"https://github.com/acusti/uikit/tree/main/packages/vite-plugin-svg-react#readme","bugs":{"url":"https://github.com/acusti/uikit/issues"},"dist":{"shasum":"7161529d7fdbace5dd02db459ce2a6e74cf615ec","tarball":"https://registry.npmjs.org/@acusti/vite-plugin-svg-react/-/vite-plugin-svg-react-0.1.0.tgz","fileCount":6,"integrity":"sha512-9Ves5QKpVHmr0In9bIq3ANaLOHTj0DtbrL2JbXAtlAqYgqpWYn+mlUUGKWMeakLKJlFHmZZlBl9VbiQNjKB9TQ==","signatures":[{"sig":"MEQCIDgCbS1oPJjDEfnUOGx/FrDOVl0H1QKf0BxSMZuRt3xZAiAC+uMIM3QMJg2RaGswi6XdyyS6Px40eUmFXfjcjbxlqg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14395},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":"./dist/index.js","./client":{"types":"./client.d.ts"}},"gitHead":"2b6f711e23199df6e23aef0e49a446e100881ecf","scripts":{"tsc":"tsc --noEmit","test":"vitest","build":"vite build && tsc -p tsconfig.build.json"},"_npmUser":{"name":"acusti","email":"andrew@acusti.ca"},"repository":{"url":"git+https://github.com/acusti/uikit.git","type":"git","directory":"packages/vite-plugin-svg-react"},"_npmVersion":"11.11.1","description":"Vite ≥8 (rolldown-native) plugin that imports SVG files as typed React components via ?react","directories":{},"sideEffects":false,"_nodeVersion":"25.8.2","dependencies":{"@svgr/core":"^8.1","@svgr/plugin-jsx":"^8.1"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.0-0","vitest":"^4","typescript":"7.0.1-rc","@types/node":"^26.1.0","@types/react":"^19.2.17"},"peerDependencies":{"vite":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vite-plugin-svg-react_0.1.0_1783121502639_0.21159305172246512","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@acusti/vite-plugin-svg-react","version":"0.2.0","keywords":["oxc","react","rolldown","svg","svgr","ts","typescript","vite","vite-plugin"],"author":{"url":"https://www.acusti.ca","name":"andrew patton","email":"andrew@acusti.ca"},"license":"Unlicense","_id":"@acusti/vite-plugin-svg-react@0.2.0","maintainers":[{"name":"acusti","email":"andrew@acusti.ca"}],"homepage":"https://github.com/acusti/uikit/tree/main/packages/vite-plugin-svg-react#readme","bugs":{"url":"https://github.com/acusti/uikit/issues"},"dist":{"shasum":"f005137bea0ab2131e0d9b15d169218d8ac8cd52","tarball":"https://registry.npmjs.org/@acusti/vite-plugin-svg-react/-/vite-plugin-svg-react-0.2.0.tgz","fileCount":9,"integrity":"sha512-6/L8TatL+bw34+8QnOcPJfXdrujw7SHHZ38eEsP8WYFln/3lPAR8btwn/W0LYxR99Igs/CDyNj3TOAH1rpOetA==","signatures":[{"sig":"MEQCIFVUscp8OLqXcpbNZDKwYEez5qzb3KqqtNCcDEx7K1h5AiAMgY8zEK6ETgYDZyDNXrYIh2fRWq6sNN1xZypZBesNRQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106851},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":"./dist/index.js","./client":{"types":"./client.d.ts"}},"gitHead":"cb446b9c733c95518821bd633961f9de90e5d3be","scripts":{"tsc":"tsc --noEmit","test":"vitest","build":"vite build && tsc -p tsconfig.build.json"},"_npmUser":{"name":"acusti","email":"andrew@acusti.ca"},"repository":{"url":"git+https://github.com/acusti/uikit.git","type":"git","directory":"packages/vite-plugin-svg-react"},"_npmVersion":"11.11.1","description":"Vite ≥8 (rolldown-native) plugin that imports SVG files as typed React components via ?react","directories":{},"sideEffects":false,"_nodeVersion":"25.8.2","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.0-0","react":"^19","vitest":"^4","happy-dom":"^20.4.0","react-dom":"^19","typescript":"^7","@types/node":"^26.1.0","@types/react":"^19.2.17","@testing-library/react":"^16.3.2"},"peerDependencies":{"vite":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vite-plugin-svg-react_0.2.0_1787541566115_0.7967001416651169","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@acusti/vite-plugin-svg-react","version":"0.3.0","keywords":["oxc","react","rolldown","svg","svgr","ts","typescript","vite","vite-plugin"],"author":{"url":"https://www.acusti.ca","name":"andrew patton","email":"andrew@acusti.ca"},"license":"Unlicense","_id":"@acusti/vite-plugin-svg-react@0.3.0","maintainers":[{"name":"acusti","email":"andrew@acusti.ca"}],"homepage":"https://github.com/acusti/uikit/tree/main/packages/vite-plugin-svg-react#readme","bugs":{"url":"https://github.com/acusti/uikit/issues"},"dist":{"shasum":"4a7bfda3c296024591d0038b47dbed4058fcf6d5","tarball":"https://registry.npmjs.org/@acusti/vite-plugin-svg-react/-/vite-plugin-svg-react-0.3.0.tgz","fileCount":11,"integrity":"sha512-glktuTVkAHfcumf4Tu1WlxU1bPakMEgGX09sk1AEoCpMec8qDAMCm6TLZUo8i+1pPQMtXWoIjjMceiBdEPGraw==","signatures":[{"sig":"MEQCIHuZ/56tka66UHP5+phnNbGakjQzdWP3/8tf60KenVf2AiBwJeQlnO5N7av+UMNlWzlKTvlqEwanZMPt8Ipa2jFg+g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDhSODtht2m+uZZjWXXNm0ummLotalQaHzX3svfVsckPQIhAJABGllTMY5hzEO46F1e/90NQynWDjf9x10jRDyDf+mv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":130503},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":"./dist/index.js","./client":{"types":"./client.d.ts"}},"gitHead":"b48cc41e1999caa66d66158f05a0aeda5580cb64","scripts":{"tsc":"tsc --noEmit","test":"vitest","build":"vite build && tsc -p tsconfig.build.json"},"_npmUser":{"name":"acusti","email":"andrew@acusti.ca"},"repository":{"url":"git+https://github.com/acusti/uikit.git","type":"git","directory":"packages/vite-plugin-svg-react"},"_npmVersion":"11.11.1","description":"Vite ≥8 (rolldown-native) plugin that imports SVG files as typed React components via ?react","directories":{},"sideEffects":false,"_nodeVersion":"25.8.2","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.0-0","react":"^19","vitest":"^4","happy-dom":"^20.4.0","react-dom":"^19","@oxvg/napi":"^0.0.7","typescript":"^7","@types/node":"^26.1.0","@types/react":"^19.2.17","@testing-library/react":"^16.3.2"},"peerDependencies":{"vite":">=8.0.0","@oxvg/napi":">=0.0.7"},"peerDependenciesMeta":{"@oxvg/napi":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/vite-plugin-svg-react_0.3.0_1789088954954_0.5116108353630313","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"_id":"@acusti/vite-plugin-svg-react@0.4.0","bugs":{"url":"https://github.com/acusti/uikit/issues"},"dist":{"shasum":"3817aca5621c237ba59da90379223bf2699ac2d2","tarball":"https://registry.npmjs.org/@acusti/vite-plugin-svg-react/-/vite-plugin-svg-react-0.4.0.tgz","fileCount":11,"integrity":"sha512-VACKEZAa5tYDtcJ0MwUbaeJbubEuOah09bx0zDofJB0wbBnK6scRgxDLCpGoihXsl2wX5Mbldw6cM0D+36KjNA==","signatures":[{"sig":"MEYCIQCVpWa9ZJAAgCuNkf3d+nhyt9hnTth5mSvk+9inGzmKrwIhAL8i1e9XL521tu6PJj3h0FqFo8E71u2MyILvcAe+DKsi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHmj5TfPQ5ipQBBKynKU8YwHR0PYZQhNwnqHYvYCEHGJAiA4DO+0G34S0E+pSmr4syneQ+tg5b3VHur7R4AVFYNDVA=="}],"unpackedSize":147557},"main":"./dist/index.js","name":"@acusti/vite-plugin-svg-react","type":"module","types":"./dist/index.d.ts","author":{"url":"https://www.acusti.ca","name":"andrew patton","email":"andrew@acusti.ca"},"exports":{".":"./dist/index.js","./client":{"types":"./client.d.ts"}},"gitHead":"b4dc8a0b7e8deaf74877d35d9b8d98ba794ad0e5","license":"Unlicense","scripts":{"tsc":"tsc --noEmit","test":"vitest","build":"vite build && tsc -p tsconfig.build.json"},"version":"0.4.0","_npmUser":{"name":"acusti","email":"andrew@acusti.ca"},"homepage":"https://github.com/acusti/uikit/tree/main/packages/vite-plugin-svg-react#readme","keywords":["oxc","react","rolldown","svg","svgr","ts","typescript","vite","vite-plugin"],"repository":{"url":"git+https://github.com/acusti/uikit.git","type":"git","directory":"packages/vite-plugin-svg-react"},"_npmVersion":"11.11.1","description":"Vite ≥8 (rolldown-native) plugin that imports SVG files as typed React components via ?react","directories":{},"maintainers":[{"name":"acusti","email":"andrew@acusti.ca"}],"sideEffects":false,"_nodeVersion":"25.8.2","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.0-0","react":"^19","vitest":"^4","happy-dom":"^20.4.0","react-dom":"^19","@oxvg/napi":"^0.0.7","typescript":"^7","@types/node":"^26.1.0","@types/react":"^19.2.17","@testing-library/react":"^16.3.2"},"peerDependencies":{"vite":">=8.0.0","@oxvg/napi":">=0.0.7"},"peerDependenciesMeta":{"@oxvg/napi":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vite-plugin-svg-react_0.4.0_1789152954993_0.3550777186880194"}}},"time":{"created":"2026-07-03T23:31:42.438Z","modified":"2026-09-11T18:55:55.268Z","0.1.0":"2026-07-03T23:31:42.782Z","0.2.0":"2026-08-24T03:19:26.255Z","0.3.0":"2026-09-11T01:09:15.047Z","0.4.0":"2026-09-11T18:55:55.086Z"},"bugs":{"url":"https://github.com/acusti/uikit/issues"},"author":{"url":"https://www.acusti.ca","name":"andrew patton","email":"andrew@acusti.ca"},"license":"Unlicense","homepage":"https://github.com/acusti/uikit/tree/main/packages/vite-plugin-svg-react#readme","keywords":["oxc","react","rolldown","svg","svgr","ts","typescript","vite","vite-plugin"],"repository":{"url":"git+https://github.com/acusti/uikit.git","type":"git","directory":"packages/vite-plugin-svg-react"},"description":"Vite ≥8 (rolldown-native) plugin that imports SVG files as typed React components via ?react","maintainers":[{"name":"acusti","email":"andrew@acusti.ca"}],"readme":"# @acusti/vite-plugin-svg-react\n\n[![Open on npmx.dev](https://npmx.dev/api/registry/badge/version/@acusti/vite-plugin-svg-react)](https://npmx.dev/package/@acusti/vite-plugin-svg-react)\n[![Open on npmx.dev](https://npmx.dev/api/registry/badge/size/@acusti/vite-plugin-svg-react)](https://npmx.dev/package/@acusti/vite-plugin-svg-react)\n[![Open on npmx.dev](https://npmx.dev/api/registry/badge/dependencies/@acusti/vite-plugin-svg-react)](https://npmx.dev/package/@acusti/vite-plugin-svg-react)\n[![Open on npmx.dev](https://npmx.dev/api/registry/badge/downloads-month/@acusti/vite-plugin-svg-react)](https://npmx.dev/package/@acusti/vite-plugin-svg-react)\n[![Open on npmx.dev](https://npmx.dev/api/registry/badge/updated/@acusti/vite-plugin-svg-react)](https://npmx.dev/package/@acusti/vite-plugin-svg-react)\n\nA [Vite][] plugin that turns SVG files into typed React components:\n\n```tsx\nimport Icon from './icon.svg?react';\n\n<Icon className=\"icon\" aria-hidden />;\n```\n\nIt was extracted from the build tooling of [Outlyne][], where it runs in\nproduction.\n\n[vite]: https://vite.dev\n[outlyne]: https://outlyne.com\n\n## Why Vite ≥ 8 only?\n\nThis plugin requires Vite 8 and is rolldown-native, on purpose. The Vite 8\n/ [rolldown-vite][] transition left no working [SVGR][] option:\n[vite-plugin-svgr][] runs its own esbuild transform to compile the JSX that\nSVGR emits, reintroducing esbuild into an otherwise oxc/rolldown pipeline.\nThis plugin instead generates each component module directly and compiles\nit with Vite 8’s exported `transformWithOxc`, so SVG-to-React conversion is\noxc/rolldown end to end: no esbuild fallback, no version matrix, no\ncompatibility shims for older Vite versions. If you are on Vite < 8, use\n[vite-plugin-svgr][].\n\n[rolldown-vite]: https://vite.dev/guide/rolldown\n[svgr]: https://react-svgr.com\n[vite-plugin-svgr]: https://github.com/pd4d10/vite-plugin-svgr\n\n## Babel-free (and dependency-free)\n\nThe plugin converts SVG to a React component module itself — parsing the\nSVG as XML and emitting the component as JSX source — instead of delegating\nto SVGR, which parses and re-prints the module through Babel. Attribute\nconversion matches what SVGR produced (kebab-case presentation attributes\nto camelCase, `class` → `className`, `xlink:*`/`xml:*` to their React prop\nnames, `data-*`/`aria-*` passed through, `style` strings to style objects),\nso the rendered components are the same, apart from the SVGR bugs fixed\nbelow. What consumers get out of it:\n\n- **Zero dependencies:** no `@svgr/*` and no `@babel/*` in the dependency\n  tree, which removes dozens of packages from a typical install.\n- **Fast cold transforms:** emitting the module as a string takes\n  microseconds, and compiling it with oxc takes about a millisecond, so the\n  first `.svg?react` import costs single-digit milliseconds instead of the\n  hundreds of milliseconds it takes to load and warm up a Babel pipeline.\n- **Seven SVGR conversion bugs fixed:** CDATA sections are preserved rather\n  than dropped; `px` values inside a `style` attribute stay strings (SVGR\n  stripped the unit, and React only adds it back to the CSS properties that\n  take one, so `line-height: 20px` became a multiplier of 20 and\n  `--gap: 6px` a bare `6`); semicolons inside `url(…)` and inside CSS\n  comments no longer truncate a style value, and the comments themselves\n  are removed rather than left in as invalid CSS; attribute values\n  containing double quotes no longer emit invalid JSX; whitespace between\n  the children of a text-content element survives, so\n  `<tspan>A</tspan> <tspan>B</tspan>` still renders “A B” rather than “AB”;\n  and attribute values become numbers only when that round-trips, so\n  `id=\"001\"` stays `001` rather than turning into `1` and breaking the\n  `<use href=\"#001\">` pointing at it.\n\n[SVGO][]-style optimization is available as an opt-in: the `optimize`\noption below runs each SVG through [OXVG][] — the Rust, SVGO-compatible SVG\ntoolchain — ahead of component generation. Its dependency is optional, so\nthe default install stays dependency-free.\n\n[svgo]: https://github.com/svg/svgo\n[oxvg]: https://github.com/noahbald/oxvg\n\n## Usage\n\n```\nnpm install --save-dev @acusti/vite-plugin-svg-react\n# or\nyarn add --dev @acusti/vite-plugin-svg-react\n```\n\nAdd the plugin to your vite config:\n\n```ts\n// vite.config.ts\nimport svgReact from '@acusti/vite-plugin-svg-react';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n    plugins: [svgReact()],\n});\n```\n\nThen import SVG files with the `?react` query suffix to get a React\ncomponent. The default export is a component that spreads its props onto\nthe root `<svg>` element:\n\n```tsx\nimport Logo from './logo.svg?react';\n\nexport function Header() {\n    return <Logo width={32} height={32} role=\"img\" />;\n}\n```\n\nNote that react isn’t a dependency or peer dependency of this package: the\nemitted components import `react/jsx-runtime` (or `react/jsx-dev-runtime`\nin dev), which your app provides.\n\n### TypeScript\n\nThe package ships a `client.d.ts` that types `*.svg?react` imports as\n`React.FC<React.SVGProps<SVGSVGElement>>`. Wire it up either via the\n`types` field in your tsconfig:\n\n```json\n{\n    \"compilerOptions\": {\n        \"types\": [\"@acusti/vite-plugin-svg-react/client\"]\n    }\n}\n```\n\nOr via a triple-slash directive in a `.d.ts` file that’s included in your\nproject (e.g. `src/vite-env.d.ts`):\n\n```ts\n/// <reference types=\"@acusti/vite-plugin-svg-react/client\" />\n```\n\n### Options\n\nThe plugin takes an optional options object with two properties:\n`optimize`, documented below, and `svg`, which shapes the generated `<svg>`\nelement. `svg` supports a deliberately small subset of the [SVGR\noptions][svgr options], with the same names and semantics:\n\n```ts\nsvgReact({\n    svg: {\n        icon: true,\n        svgProps: { role: 'img' },\n    },\n});\n```\n\n- `dimensions: false` removes `width`/`height` from the root `<svg>`, and\n  wins over `icon` if you set both\n- `icon` sets `width`/`height` to `1em` (`true`) or to the value you pass,\n  and does nothing alongside `dimensions: false`\n- `svgProps` adds extra props to the root `<svg>` (string values, or\n  `{expression}` strings inserted verbatim)\n\n#### `optimize`\n\nOff by default. Set `optimize: true` to run each SVG through OXVG before\nit’s converted to a component:\n\n```\nnpm install --save-dev @oxvg/napi\n```\n\n```ts\nsvgReact({ optimize: true });\n```\n\n`@oxvg/napi` is an optional peer dependency: install it to use `optimize`,\nand the plugin stays dependency-free if you don’t. Optimization runs on the\nraw SVG source, so the rest of the pipeline is unchanged by it.\n\n`optimize: true` runs OXVG’s default preset, which leaves `viewBox` alone\n(unlike SVGO’s `preset-default`), plus `prefixIds`. Ids come out minified\nand prefixed with the file’s base name and a 4-character hash of its path\nrelative to the vite root, so they stay unique when components are inlined\ntogether and come out the same on every machine:\n\n```\n// src/icons/arrow.svg, as authored\n<linearGradient id=\"arrowGradient\">…</linearGradient>\n<path fill=\"url(#arrowGradient)\"/>\n\n// optimized\n<linearGradient id=\"arrow-58f3_a\">…</linearGradient>\n<path fill=\"url(#arrow-58f3_a)\"/>\n```\n\nEvery reference inside the file — `href=\"#…\"`, `url(#…)`, `aria-labelledby`\n— is rewritten to match. Class names are left as you wrote them, with one\nexception: a class the SVG’s own `<style>` element styles is folded into a\n`style` attribute and dropped (`inlineStyles`, see the end of this\nsection).\n\nTo avoid issues, don’t reference an id inside an SVG from outside it (app\nCSS, `getElementById`, an `aria-labelledby` on another element). An `id`\nthat isn’t referenced anywhere else in the file is removed, and the\nminified part isn’t stable — which id becomes `a` depends on the order of\nreferences in the file, so an edit to the SVG can reassign it. For an id\nthe rest of your app needs, put it on the component instead. Props spread\nonto the root `<svg>`, so an `id` prop lands there, and everything inside\nis reachable from it by class:\n\n```tsx\nimport Hero from './hero.svg?react';\n\nfunction Banner() {\n    return <Hero id=\"hero-art\" />;\n}\n```\n\n```css\n#hero-art .wheel {\n    animation: spin 4s linear infinite;\n}\n```\n\nIf an SVG’s ids have to stay as authored, leave `cleanupIds` out and pass\nthe rest of the preset as `jobs`:\n\n```ts\nimport { extend } from '@oxvg/napi';\n\n// the default preset minus cleanupIds\nconst { cleanupIds, ...jobs } = extend({ type: 'Default' });\n\nsvgReact({ optimize: { jobs } });\n```\n\nOr keep the default and leave those files out of the pass. An object form\nof the option takes `include` and `exclude` patterns — a glob, a RegExp, or\nan array of either, matched with Vite’s `createFilter` against each SVG’s\npath relative to the vite root (`icons/star.svg`), for RegExps and globs\nalike — alongside the `jobs` to run. Each is optional: with no `jobs`, the\ndefault preset runs; with no `include`, every SVG that `exclude` doesn’t\nmatch is optimized. Excluded SVGs still become components, just from their\nsource as written:\n\n```ts\nsvgReact({\n    optimize: {\n        exclude: ['src/illustrations/**', /\\.animated\\.svg$/],\n        include: 'src/**',\n    },\n});\n```\n\n`jobs` is handed to OXVG’s `optimise` as-is. An OXVG job list is the\ncomplete list of the optimizations to run, not a set of overrides on top of\na preset, so this one runs a single optimization and nothing else:\n\n```ts\nsvgReact({ optimize: { jobs: { collapseGroups: { field0: true } } } });\n```\n\nThe plugin owns one key in the list, `prefixIds`. A job list with\n`cleanupIds` gets the per-file `prefixIds` that `optimize: true` uses\nunless it brings its own, so a customized preset stays as collision-safe as\nthe default one, and a list without `cleanupIds` isn’t prefixed. In a\n`prefixIds` of your own, a `prefix` of `{ type: 'Default' }` — which is\nmeaningless to `optimise` without a path — resolves to that same per-file\nprefix, so this is the default preset with `prefixIds` also prefixing class\nnames:\n\n```ts\nimport { extend } from '@oxvg/napi';\n\nsvgReact({\n    optimize: {\n        jobs: extend(\n            { type: 'Default' },\n            {\n                prefixIds: {\n                    delim: '_',\n                    prefix: { type: 'Default' },\n                    prefixClassNames: true,\n                    prefixIds: true,\n                },\n            },\n        ),\n    },\n});\n```\n\nA `prefix` of `{ type: 'Prefix', field0: 'app' }` or `{ type: 'None' }` is\nleft alone.\n\nFor the default preset with a change to it, build the job list with OXVG’s\nown `extend`:\n\n```ts\nimport { extend } from '@oxvg/napi';\n\nsvgReact({\n    optimize: {\n        jobs: extend(\n            { type: 'Default' },\n            { removeDesc: { removeAny: true } },\n        ),\n    },\n});\n```\n\n`extend` only adds, so drop a job by leaving it out of the object you pass:\n\n```ts\nimport { extend } from '@oxvg/napi';\n\n// the default preset minus inlineStyles\nconst { inlineStyles, ...jobs } = extend({ type: 'Default' });\n\nsvgReact({ optimize: { jobs } });\n```\n\n`jobs` is typed as a plain object rather than as OXVG’s `Jobs`, so that\nthis package’s types don’t reference a dependency most installs won’t have.\nFor a typed job list, annotate it where you write it:\n\n```ts\nimport type { Jobs } from '@oxvg/napi';\n\nsvgReact({\n    optimize: { jobs: { removeDesc: { removeAny: true } } satisfies Jobs },\n});\n```\n\nTwo more things about OXVG itself:\n\n1. A job name it doesn’t recognize is ignored silently, which is what\n   `satisfies Jobs` above is for.\n2. `inlineStyles`, in the default preset, folds a rule from an SVG’s own\n   `<style>` element into a `style` attribute and drops the `class` that\n   matched it — usually a generated name like `.cls-1`, but if you style by\n   class name from your app’s CSS and the SVG carries its own rule for that\n   class, leave `inlineStyles` out as above.\n\n#### SVG files the `optimize` option rejects\n\nThis plugin’s own parser is deliberately tolerant of markup that real SVG\nfiles contain but XML rejects. OXVG’s parser runs first and isn’t, so\nturning `optimize` on narrows what builds. Each case fails loudly, naming\nthe file and the line, and each still builds with `optimize` off:\n\n- **A doctype whose internal subset declares entities the root element\n  references** — how classic Illustrator (10–CS4) wrote its Adobe\n  namespaces. OXVG rejects any document with a DTD, so the prolog is\n  blanked before it gets there, and the references outlive it:\n  `unknown entity reference 'ns_extend'`.\n- **An unknown entity name** anywhere, such as the HTML-only `&nbsp;`,\n  which XML doesn’t define. Without `optimize` these pass through\n  literally; with it, `unknown entity reference 'nbsp'`.\n- **A minimized attribute** (`<svg hidden>`), which is legal inline in HTML\n  but not in XML. Without `optimize` it reads as `hidden=\"\"`; with it,\n  `expected '=' not '>'`.\n\nIf you hit one of these, it’s the option and not your file: normalize the\nSVG once (`svgo`, or any XML formatter) or don’t use the `optimize` option.\n\nThe module wrapper is fixed: a typed component that spreads its props onto\nthe root `<svg>`, exported as the default export. Any other option throws\nat config time — rejecting unknown options loudly beats silently generating\ncomponents that don’t match your configuration. That includes the SVGR\noptions this plugin deliberately doesn’t carry, most of which have direct\nreplacements:\n\n- `ref`: unnecessary on React 19, where `ref` is a regular prop — the props\n  spread already delivers it to the `<svg>` DOM node\n- `memo`: wrap at the use site (`memo(Icon)`)\n- `exportType`/`namedExport`: the default export is the only export, which\n  is also the only shape `client.d.ts` types\n- `typescript`: the emitted module is compiled immediately, so this had no\n  observable effect\n- `svgoConfig`: the `optimize` option above, in OXVG’s config vocabulary\n  rather than SVGO’s\n- `jsxRuntime`, `expandProps`, `titleProp`, `descProp`,\n  `replaceAttrValues`, and SVGR’s remaining pipeline options (`plugins`,\n  `template`): not supported\n\nMigrating from vite-plugin-svgr (or from this plugin’s svgr-based 0.1\nrelease): the old `svgrOptions` key throws with a message pointing here —\nmove `icon`, `svgProps`, and `dimensions` under `svg` and drop the rest.\n\n[svgr options]: https://react-svgr.com/docs/options/\n\n## Why the dev JSX runtime in dev matters\n\nWhen serving (`vite dev`), the plugin compiles JSX against\n`react/jsx-dev-runtime`; when building, against `react/jsx-runtime`. This\nmatches what Vite’s main transform pipeline does for your app’s own\ncomponents, it isn’t configurable, and it’s the plugin’s hard-won\ncorrectness feature.\n\nHere’s why: Vite’s dependency scanner treats `.svg` imports as assets and\nnever crawls the virtual modules this plugin creates. If your app imports\nReact only via JSX, the scanner discovers `react/jsx-dev-runtime` from your\ncomponents at startup — but nothing else imports `react/jsx-runtime` in\ndev. If the SVG components were compiled against the production runtime,\n`react/jsx-runtime` would be a dependency that only these uncrawlable\nvirtual modules import, so on a cold optimizer cache it gets discovered\nmid-first-request, forcing a re-optimization while the first request is in\nflight.\n\nIn SSR environments (e.g. [@cloudflare/vite-plugin][]’s workerd runtime),\nthat mid-request re-optimization bumps the `?v=` hash of every optimized\nchunk under the in-flight render, splitting React into two module\ninstances, which fails with errors like\n`Cannot read properties of null (reading 'useContext')` — a 500 on the\nfirst cold request. Emitting the dev runtime in dev keeps these modules on\nthe same optimized dependency graph as the rest of your app, so they never\ntrigger that path.\n\nAs defense in depth, SSR users can additionally pin the React family in\ntheir server environment’s optimizeDeps so the optimizer never discovers\nanything React-related late:\n\n```ts\nenvironments: {\n    ssr: {\n        optimizeDeps: {\n            include: [\n                'react',\n                'react/jsx-runtime',\n                'react/jsx-dev-runtime',\n                'react-dom/server',\n            ],\n        },\n    },\n},\n```\n\n[@cloudflare/vite-plugin]:\n    https://github.com/cloudflare/workers-sdk/tree/main/packages/vite-plugin-cloudflare\n\n## FAQ\n\n### Why `?react` and not import attributes (`with { type: 'react' }`)?\n\nThree reasons:\n\n1. **TypeScript types modules by their specifier string**, so\n   `declare module '*.svg?react'` gives every `?react` import the right\n   component type. Import attributes are invisible to the type system:\n   there’s no way to say “`*.svg` imported with `type: 'react'` is a\n   component, but plain `*.svg` is a URL string.”\n2. **Hosts are spec-required to throw on unknown attribute types**, and\n   Vite’s dev server serves your modules as near-native ESM, rewriting only\n   the specifiers. A custom import attribute would reach the browser intact\n   and hard-fail there.\n3. **Query suffixes are Vite’s own blessed convention** for import\n   transforms (`?url`, `?raw`, `?inline`), so `?react` behaves like the\n   rest of the ecosystem and composes with Vite’s asset handling.\n","readmeFilename":"README.md"}