Gatsby: What's the preferred way to handle SVG sprites?

Created on 10 Mar 2019  路  3Comments  路  Source: gatsbyjs/gatsby

Summary

What's the best way of creating an svg sprite and adding that to the document body for use.

Relevant information

I can't get svg sprites from a 3rd party package working.

I have two files that I import in to my gatsby-browser.js file from an npm package as follows:

import 'belle-js/lib/icons.svg'
import 'belle-js/lib/icons-rich.svg'

I'm processing this files using the webpack loader, svg-sprite-loader, and am expecting for these files to be output to a place I can reference from my src/layouts/Layouts.jsx. I'm trying to append the svg sprite to the document body using the react-inlinesvg module i.e. via <SVG src="iconpath"></SVG>.

However, when I run the gatsby develop, no files are ever output.
When I run gatsby build, i get a sprite.svg file output into the public directory but I when I try to load the site after running gatsby serve, I get the following error: https://reactjs.org/docs/error-decoder.html/?invariant=130&args[]=undefined&args[]=, which I suspect is because the sprite.svg file isn't being properly referenced by the react-inlinesvg module, which looks like the following:

<SVG icon="./sprite.svg" uniquifyIDS={false}></SVG

Can anyone recommend a straight forward way of handling this type of SVG sprite?
Or
Can anyone point in the direction of what i'm doing wrong?

Environment (if relevant)


  System:
    OS: macOS 10.14.3
    CPU: (4) x64 Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 8.13.0 - ~/.nvm/versions/node/v8.13.0/bin/node
    Yarn: 1.12.3 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v8.13.0/bin/npm
  Languages:
    Python: 2.7.10 - /usr/bin/python
  Browsers:
    Chrome: 72.0.3626.121
    Firefox: 65.0.1
    Safari: 12.0.3
  npmPackages:
    gatsby: ^2.1.19 => 2.1.19 
    gatsby-plugin-manifest: ^2.0.13 => 2.0.13 
    gatsby-plugin-offline: ^2.0.5 => 2.0.18 
    gatsby-plugin-polyfill-io: ^1.0.5 => 1.0.5 
    gatsby-plugin-react-helmet: ^3.0.0 => 3.0.4 
    gatsby-plugin-sass: ^2.0.1 => 2.0.5 
    gatsby-plugin-svg-sprite: ^2.0.1 => 2.0.1 
    gatsby-react-router-scroll: ^2.0.0 => 2.0.2 

File contents (if changed)

gatsby-config.js: N/A
package.json:

{
  "name": "Gatsby",
  "description": "GatsbyJS Site",
  "version": "1.0.0",
  "author": "James Campbell <[email protected]>",
  "dependencies": {
    "@reach/router": "^1.2.1",
    "babel-plugin-transform-regenerator": "^6.26.0",
    "babel-polyfill": "^6.26.0",
    "belle": "git+https://cc7b68a81b7cef43e19292231b899771aaeff13a:[email protected]/Ellevest/BelleJS.git",
    "belle-js": "git+https://cc7b68a81b7cef43e19292231b899771aaeff13a:[email protected]/Ellevest/BelleJS.git#jc-fixReactInlineSVGServerRenderError",
    "classnames": "^2.2.6",
    "cloudinary-core": "^2.5.0",
    "cloudinary-react": "^1.1.0",
    "extract-text-webpack-plugin": "^3.0.2",
    "gatsby": "^2.1.19",
    "gatsby-plugin-manifest": "^2.0.13",
    "gatsby-plugin-offline": "^2.0.5",
    "gatsby-plugin-polyfill-io": "^1.0.5",
    "gatsby-plugin-react-helmet": "^3.0.0",
    "gatsby-plugin-sass": "^2.0.1",
    "gatsby-plugin-svg-sprite": "^2.0.1",
    "gatsby-react-router-scroll": "^2.0.0",
    "js-cookie": "^2.2.0",
    "node-sass": "^4.9.4",
    "prop-types": "^15.6.2",
    "react": "^16.8.3",
    "react-dom": "^16.8.3",
    "react-helmet": "^5.2.0",
    "react-redux": "^5.0.7",
    "react-router": "^4.3.1",
    "react-slick": "^0.23.2",
    "redux": "^4.0.0",
    "redux-cookie": "^0.5.9",
    "redux-logger": "^3.0.6",
    "sass-resources-loader": "^1.3.3",
    "svg-sprite-loader": "^4.1.3",
    "typeface-lato": "^0.0.54",
    "typeface-merriweather": "^0.0.54",
    "typeface-playfair-display": "^0.0.54"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "serve": "gatsby serve",
    "format": "prettier --write '**/*.js'",
    "test": "jest"
  },
  "devDependencies": {
    "@babel/core": "^7.2.0",
    "babel-core": "^7.0.0-0",
    "babel-jest": "^23.6.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-gatsby": "^0.1.6",
    "babel-preset-react": "^6.24.1",
    "enzyme": "^3.7.0",
    "enzyme-adapter-react-16": "^1.7.0",
    "eslint": "^5.15.0",
    "eslint-config-prettier": "^4.1.0",
    "eslint-plugin-prettier": "^3.0.1",
    "file-loader": "^3.0.1",
    "identity-obj-proxy": "^3.0.0",
    "jest": "^23.6.0",
    "prettier": "^1.16.4",
    "react-test-renderer": "^16.6.3",
    "susy": "^2.2.12"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/gatsbyjs/gatsby-starter-default"
  },
  "jest": {
    "transform": {
      ".(js|jsx)": "babel-jest"
    },
    "testRegex": "(\\.(test|spec))\\.(jsx|js)$",
    "testPathIgnorePatterns": [
      "/node_modules/",
      "/.cache/"
    ],
    "setupFiles": [
      "./setupTests.js"
    ]
  }
}

gatsby-node.js:
```
/* eslint-disable no-undef /
/
*

// You can delete this file if you're not using it
const path = require('path')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin')

exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
const config = getConfig()

config.resolve.alias = {
...config.resolve.alias,
'@@root': path.resolve(__dirname, 'src'),
'@@redux': path.resolve(__dirname, 'src', 'redux'),
'@@layouts': path.resolve(__dirname, 'src', 'layouts'),
'@@analytics': path.resolve(__dirname, 'src', 'analytics'),
'@@components': path.resolve(__dirname, 'src', 'ui', 'components'),
'@@modules': path.resolve(__dirname, 'src', 'ui', 'modules'),
'@@views': path.resolve(__dirname, 'src', 'ui', 'views'),
'@@templates': path.resolve(__dirname, 'src', 'ui', 'templates'),
'@@staticContent': path.resolve(__dirname, 'src', 'staticContent'),
'@@utils': path.resolve(__dirname, 'src', 'utils'),
'@@contextProviders': path.resolve(__dirname, 'src', 'contextProviders'),
'@@shared': path.resolve(__dirname, 'src', 'shared'),
}

config.module.rules = [
...config.module.rules,
{
test: /.module.(css|scss)$/,
loader: 'sass-resources-loader',
options: {
resources: [
path.join(__dirname, '/node_modules/belle-js/src/styles/settings/_breakpoints.scss'),
path.join(__dirname, '/node_modules/belle-js/src/styles/settings/_colors.scss'),
path.join(__dirname, '/node_modules/belle-js/src/styles/settings/_fonts.scss'),
path.join(__dirname, '/node_modules/belle-js/src/styles/base/_mixins.scss'),
path.join(__dirname, '/styles/_angled_edge.scss'),
path.join(__dirname, '/styles/_variables.scss'),
path.join(__dirname, '/styles/_mixins.scss'),
],
},
},
{
test: /(icons|icons-rich).svg$/,
loader: 'svg-sprite-loader',
options: {
extract: true,
publicPath: './'
},
},
],

config.plugins = [
  ...config.plugins,
  new SpriteLoaderPlugin()
]

actions.replaceWebpackConfig(config)
}

exports.onCreateBabelConfig = ({ actions }) => {
actions.setWebpackConfig({
plugins: ['transform-regenerator'],
})
}

`gatsby-browser.js`:

/**

// You can delete this file if you're not using it
import 'typeface-lato'
import 'typeface-merriweather'
import 'typeface-playfair-display'

import './styles/reset.css'
import './styles/ellevestMarketing.scss'

import 'belle-js/lib/icons.svg'
import 'belle-js/lib/icons-rich.svg'

import wrapWithProvider from './src/helpers/wrapWithProvider'

export const wrapRootElement = wrapWithProvider
`` gatsby-ssr.js`: N/A

stale? question or discussion

Most helpful comment

This is what I do with Feather Icons:

/components/FeatherIcon.js

import React from 'react'
import PropTypes from 'prop-types'
import featherSprite from 'feather-icons/dist/feather-sprite.svg'

const FeatherIcon = ({ name, color, size, ...restProps }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width={size}
    height={size}
    viewBox="0 0 24 24"
    fill="none"
    stroke={color}
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    {...restProps}
  >
    <use xlinkHref={`${featherSprite}#${name}`} />
  </svg>
)

export default FeatherIcon

FeatherIcon.propTypes = {
  name: PropTypes.string.isRequired,
  color: PropTypes.string,
  size: PropTypes.number,
}

FeatherIcon.defaultProps = {
  color: 'currentColor',
  size: 24,
}

/pages/index.js

import React from 'react'
import FeatherIcon from '../components/FeatherIcon'

export default () => (
  <FeatherIcon
    name="circle"
  />
)

All 3 comments

This is what I do with Feather Icons:

/components/FeatherIcon.js

import React from 'react'
import PropTypes from 'prop-types'
import featherSprite from 'feather-icons/dist/feather-sprite.svg'

const FeatherIcon = ({ name, color, size, ...restProps }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width={size}
    height={size}
    viewBox="0 0 24 24"
    fill="none"
    stroke={color}
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    {...restProps}
  >
    <use xlinkHref={`${featherSprite}#${name}`} />
  </svg>
)

export default FeatherIcon

FeatherIcon.propTypes = {
  name: PropTypes.string.isRequired,
  color: PropTypes.string,
  size: PropTypes.number,
}

FeatherIcon.defaultProps = {
  color: 'currentColor',
  size: 24,
}

/pages/index.js

import React from 'react'
import FeatherIcon from '../components/FeatherIcon'

export default () => (
  <FeatherIcon
    name="circle"
  />
)

Hiya!

This issue has gone quiet. Spooky quiet. 馃懟

We get a lot of issues, so we currently close issues after 30 days of inactivity. It鈥檚 been at least 20 days since the last update here.

If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

Thanks for being a part of the Gatsby community! 馃挭馃挏

Hey again!

It鈥檚 been 30 days since anything happened on this issue, so our friendly neighborhood robot (that鈥檚 me!) is going to close it.

Please keep in mind that I鈥檓 only a robot, so if I鈥檝e closed this issue in error, I鈥檓 HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.

Thanks again for being part of the Gatsby community!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

3CordGuy picture 3CordGuy  路  3Comments

rossPatton picture rossPatton  路  3Comments

KyleAMathews picture KyleAMathews  路  3Comments

Oppenheimer1 picture Oppenheimer1  路  3Comments

hobochild picture hobochild  路  3Comments