Repository: smooth-code/svgr (js)

Issue:
Issue with loading SVG sprite
I'm trying to load an SVG file as a React component. I found a PR https://github.com/facebookincubator/create-react-app/pull/3718 by @iansu that solves the problem. 

However there is an issue with reading the SVG file contents.

**Issue**
I have the following SVG file (it was generated by [svg-sprite]):(https://www.npmjs.com/package/svg-sprite)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<svg width="0" height="0" style="position:absolute">
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="filter">
    <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </symbol>
</svg>
```
which is being imported as:
![image](https://user-images.githubusercontent.com/3687215/34912728-9e7ea1fe-f93c-11e7-9def-e3c9a024726d.png)
As you see the `<svg />` element is empty.

**Workaround**
I was able to find a workaround to the above. All works fine if I add `<defs />` element that includes `<style />` element:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<svg width="0" height="0" style="position:absolute">
  <defs><style></style></defs>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="filter">
    <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </symbol>
</svg>
```
which returns a proper `<svg />` element and its contents:
![image](https://user-images.githubusercontent.com/3687215/34912749-1491ccc2-f93d-11e7-95b4-508050571f08.png)

**Expected scenario**
The SVG example from _Issue_ section should be loaded correctly (with its contents) without adding some extra tags.

Pull request:
feat: add option keepUselessDefs
Fix #36

Patch:
diff --git a/README.md b/README.md
index aab8b95..419b650 100644
--- a/README.md
+++ b/README.md
@@ -91,13 +91,14 @@ Options:
   --no-prettier                    disable Prettier (default: true)
   --template <file>                specify a custom template to use
   --no-expand-props                disable props expanding (default: true)
-  --ids                            keep ids within the svg
   --ref                            add svgRef prop to svg
   --icon                           use "1em" as width and height
   --no-view-box                    remove viewBox (default: true)
   --native                         add react-native support with react-native-svg
   --replace-attr-value [old=new]   replace an attribute value
   -p, --precision <value>          set the number of digits in the fractional part (svgo)
+  --ids                            keep ids within the svg (svgo)
+  --keep-useless-defs              keep elements of <defs> without id (svgo)
   --no-title                       remove title tag (svgo) (default: true)
   --tab-width                      specify the number of spaces by indentation-level (prettier)
   --use-tabs                       indent lines with tabs instead of spaces (prettier)
@@ -389,6 +390,15 @@ Set number of digits in the fractional part. See
 | ------- | ------------------- | ------------------ |
 | `3`     | `--precision <int>` | `precision: <int>` |
 
+### Useless Defs
+
+Keep elements of `<defs>` without `id`. It also keep unused symbols. See
+[SVGO `removeUselessDefs` plugin](https://github.com/svg/svgo).
+
+| Default | CLI Override          | API Override              |
+| ------- | --------------------- | ------------------------- |
+| `false` | `--keep-useless-defs` | `keepUselessDefs: <bool>` |
+
 ### Title
 
 Remove the title from SVG. See
diff --git a/src/cli/index.js b/src/cli/index.js
index 7e5ff1e..e529ffc 100644
--- a/src/cli/index.js
+++ b/src/cli/index.js
@@ -23,7 +23,6 @@ program
   .option('--no-prettier', 'disable Prettier')
   .option('--template <file>', 'specify a custom template to use')
   .option('--no-expand-props', 'disable props expanding')
-  .option('--ids', 'keep ids within the svg')
   .option('--ref', 'add svgRef prop to svg')
   .option('--icon', 'use "1em" as width and height')
   .option('--no-view-box', 'remove viewBox')
@@ -37,6 +36,8 @@ program
     '-p, --precision <value>',
     'set the number of digits in the fractional part (svgo)',
   )
+  .option('--ids', 'keep ids within the svg (svgo)')
+  .option('--keep-useless-defs', 'keep elements of <defs> without id (svgo)')
   .option('--no-title', 'remove title tag (svgo)')
   .option(
     '--tab-width',
diff --git a/src/configToOptions.js b/src/configToOptions.js
index 8023b81..1a211f3 100644
--- a/src/configToOptions.js
+++ b/src/configToOptions.js
@@ -20,6 +20,7 @@ const defaultConfig = {
   replaceAttrValues: [],
   expandProps: true,
   title: true,
+  keepUselessDefs: false,
   ids: false,
   precision: 3, // default to svgo
   semi: undefined, // default to prettier
@@ -56,6 +57,7 @@ function configToOptions(config = {}) {
     if (!config.title || config.icon) plugins.push({ removeTitle: {} })
     else if (config.title) plugins.push({ removeTitle: false })
     if (config.viewBox) plugins.push({ removeViewBox: false })
+    if (config.keepUselessDefs) plugins.push({ removeUselessDefs: false })
     if (config.ids) plugins.push({ cleanupIDs: { remove: false } })
     if (config.precision === 'number')
       svgoConfig.floatPrecision = Number(svgoConfig.precision)


Test patch:
diff --git a/src/__snapshots__/index.test.js.snap b/src/__snapshots__/index.test.js.snap
index 0cca3ee..f788c01 100644
--- a/src/__snapshots__/index.test.js.snap
+++ b/src/__snapshots__/index.test.js.snap
@@ -1,5 +1,32 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`convert options keepUselessDefs: default 1`] = `
+"import React from \\"react\\";
+
+const SvgComponent = props => (
+  <svg width={0} height={0} style={{ position: \\"absolute\\" }} {...props} />
+);
+
+export default SvgComponent;
+"
+`;
+
+exports[`convert options keepUselessDefs: keepUselessDefs: true 1`] = `
+"import React from \\"react\\";
+
+const SvgComponent = props => (
+  <svg width={0} height={0} style={{ position: \\"absolute\\" }} {...props}>
+    <symbol viewBox=\\"0 0 24 24\\">
+      <path d=\\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\\" />
+      <path d=\\"M0 0h24v24H0z\\" fill=\\"none\\" />
+    </symbol>
+  </svg>
+);
+
+export default SvgComponent;
+"
+`;
+
 exports[`convert should accept initial state (for webpack) 1`] = `
 "import React from \\"react\\";
 
diff --git a/src/index.test.js b/src/index.test.js
index 62e8cd7..14fce0e 100644
--- a/src/index.test.js
+++ b/src/index.test.js
@@ -274,4 +274,20 @@ describe('convert', () => {
 
     expect(result).toMatchSnapshot()
   })
+
+  describe('options', () => {
+    it('keepUselessDefs', async () => {
+      const svgWithUselessDefs = `<?xml version="1.0" encoding="UTF-8"?>
+<svg width="0" height="0" style="position:absolute">
+  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="filter">
+    <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
+    <path d="M0 0h24v24H0z" fill="none" />
+  </symbol>
+</svg>`
+      expect(await convert(svgWithUselessDefs)).toMatchSnapshot('default')
+      expect(
+        await convert(svgWithUselessDefs, { keepUselessDefs: true }),
+      ).toMatchSnapshot('keepUselessDefs: true')
+    })
+  })
 })