vite-plugin-fast-react-svg
Version:
Turn SVG into React components, without Babel
47 lines (46 loc) • 1.44 kB
JavaScript
// src/index.ts
import { readFileSync } from "node:fs";
function svgPlugin() {
let production = false;
return {
name: "svg",
enforce: "pre",
config(_, env) {
production = env.command === "build";
},
async load(id) {
if (id.endsWith(".svg")) {
return svgToJS(readFileSync(id, "utf-8"), production);
}
}
};
}
var attributesRE = /\s([a-zA-Z0-9-:]+)=("[^"]*")/gu;
var svgToJS = (svg, production) => {
const index = svg.indexOf(">");
const content = svg.slice(index + 1, svg.indexOf("</svg>")).trim().replace(/\s+/g, " ");
let attributes = "";
for (const match of svg.slice(0, index).matchAll(attributesRE)) {
attributes += ` ${transformKey(match[1])}: ${match[2]},
`;
}
const jsxImport = production ? 'import { jsx } from "react/jsx-runtime";' : 'import { jsxDEV as jsx } from "react/jsx-dev-runtime";';
return `${jsxImport}
import { forwardRef } from "react";
export default forwardRef((props, ref) => jsx("svg", {
${attributes} ref,
...props,
dangerouslySetInnerHTML: { __html: '${content}' }
})
);`;
};
var transformKey = (key) => {
if (key.startsWith("data-")) return `"${key}"`;
const keyWithoutDashes = camelCaseOn(key, "-");
return camelCaseOn(keyWithoutDashes, ":");
};
var camelCaseOn = (string, delimiter) => string.split(delimiter).map((v, i) => i === 0 ? v : v[0].toUpperCase() + v.slice(1)).join("");
export {
svgPlugin,
svgToJS
};