Skip to content

Commit

Permalink
Add useInnerHTML option [publish]
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudBarre committed Aug 24, 2022
1 parent 8e0c11b commit 1260302
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.3.0

Added `useInnerHTML` option to use `dangerouslySetInnerHTML` for SVG contents which improve bundle size.

## 0.2.0

Breaking: Use named export instead of default export for better esm/cjs interop. Closes #2
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { defineConfig } from "vite";
import { svgPlugin } from "vite-plugin-fast-react-svg";

export default defineConfig({
plugins: [svgPlugin()],
plugins: [svgPlugin({ useInnerHTML: true })],
});
```

Expand All @@ -48,3 +48,7 @@ const Example = () => (
</>
);
```

## Options

**useInnerHTML**: Set to true to use `dangerouslySetInnerHTML` for SVG contents, which improve bundle size. Added in 0.3.0.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vite-plugin-fast-react-svg",
"description": "Turn SVG into React components, without Babel",
"version": "0.2.0",
"version": "0.3.0",
"license": "MIT",
"author": "Arnaud Barré (https://github.com/ArnaudBarre)",
"main": "dist/index.js",
Expand Down
37 changes: 26 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { readFileSync } from "fs";
import { transform } from "esbuild";
import { Plugin } from "vite";

export function svgPlugin(): Plugin {
export function svgPlugin(opts?: { useInnerHTML?: boolean }): Plugin {
return {
name: "svg",
enforce: "pre",
async load(id) {
if (id.endsWith(".svg")) {
const { code, warnings } = await transform(
svgToJSX(readFileSync(id, "utf-8")),
svgToJSX(readFileSync(id, "utf-8"), opts?.useInnerHTML),
{ loader: "jsx" }
);
for (const warning of warnings) {
Expand All @@ -27,15 +27,30 @@ export function svgPlugin(): Plugin {
};
}

export const svgToJSX = (svg: string) =>
`import React from "react";const ReactComponent = (props) => (${svg
.replace(/\s([a-z-:]*)="[^"]*"/gu, (string, key: string) => {
if (key.startsWith("data-")) return string;
const keyWithoutDashes = camelCaseOn(key, "-");
const keyWithoutDots = camelCaseOn(keyWithoutDashes, ":");
return string.replace(key, keyWithoutDots);
})
.replace(">", " {...props}>")});export default ReactComponent`;
export const svgToJSX = (svg: string, useInnerHTML?: boolean) => {
let jsx: string;
if (useInnerHTML) {
const index = svg.indexOf(">");
const content = svg
.slice(index + 1, svg.indexOf("</svg>"))
.trim()
.replace(/\s+/g, " ");
jsx = `${updatePropsCase(
svg.slice(0, index)
)} {...props} dangerouslySetInnerHTML={{ __html: '${content}' }} />`;
} else {
jsx = updatePropsCase(svg).replace(">", " {...props}>");
}
return `import React from "react";const ReactComponent = (props) => (${jsx});export default ReactComponent;`;
};

const updatePropsCase = (svg: string) =>
svg.replace(/\s([a-z-:]*)="[^"]*"/gu, (string, key: string) => {
if (key.startsWith("data-")) return string;
const keyWithoutDashes = camelCaseOn(key, "-");
const keyWithoutDots = camelCaseOn(keyWithoutDashes, ":");
return string.replace(key, keyWithoutDots);
});

const camelCaseOn = (string: string, delimiter: string) =>
string
Expand Down

0 comments on commit 1260302

Please sign in to comment.