Skip to content

Instantly share code, notes, and snippets.

@coreyward
Last active June 28, 2022 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save coreyward/be552d779986227ee1c6d8a9fd08fc9d to your computer and use it in GitHub Desktop.
Save coreyward/be552d779986227ee1c6d8a9fd08fc9d to your computer and use it in GitHub Desktop.
Inline SVGs from Sanity in Gatsby

To render the SVG, it's useful to have a wrapper component that allows passing in additional props:

import React from "react"
import { compiler } from "markdown-to-jsx"

const InlineSvg = ({ content, ...props }) => 
  compiler(content, {
    createElement: (type, elProps, children) =>
      React.createElement(type, { ...elProps, ...props }, children),
  })
module.exports = {
plugins: [
"sanity-inline-svgs",
]
}
// plugins/sanity-inline-svgs/gatsby-node.js
const crypto = require(`crypto`)
const fs = require(`fs-extra`)
const { createRemoteFileNode } = require(`gatsby-source-filesystem`)
const { default: PQueue } = require("p-queue")
const SVGO = require("svgo")
const queue = new PQueue({ concurrency: 5 })
const svgo = new SVGO({
multipass: true,
floatPrecision: 2,
plugins: [
{ removeDoctype: true },
{ removeXMLProcInst: true },
{ removeComments: true },
{ removeMetadata: true },
{ removeXMLNS: false },
{ removeEditorsNSData: true },
{ cleanupAttrs: true },
{ inlineStyles: true },
{ minifyStyles: true },
{ convertStyleToAttrs: true },
{ cleanupIDs: true },
{ prefixIds: true },
{ removeRasterImages: true },
{ removeUselessDefs: true },
{ cleanupNumericValues: true },
{ cleanupListOfValues: true },
{ convertColors: true },
{ removeUnknownsAndDefaults: true },
{ removeNonInheritableGroupAttrs: true },
{ removeUselessStrokeAndFill: true },
{ removeViewBox: false },
{ cleanupEnableBackground: true },
{ removeHiddenElems: true },
{ removeEmptyText: true },
{ convertShapeToPath: true },
{ moveElemsAttrsToGroup: true },
{ moveGroupAttrsToElems: true },
{ collapseGroups: true },
{ convertPathData: true },
{ convertTransform: true },
{ removeEmptyAttrs: true },
{ removeEmptyContainers: true },
{ mergePaths: true },
{ removeUnusedNS: true },
{ sortAttrs: true },
{ removeTitle: true },
{ removeDesc: true },
{ removeDimensions: true },
{ removeAttrs: false },
{ removeAttributesBySelector: false },
{ removeElementsByAttr: false },
{ addClassesToSVGElement: false },
{ removeStyleElement: false },
{ removeScriptElement: false },
{ addAttributesToSVGElement: false },
{ removeOffCanvasPaths: true },
{ reusePaths: false }, // note: incompatible with multipass
],
})
exports.createSchemaCustomization = ({ actions }) => {
actions.createTypes(`
type InlineSvg implements Node @noInfer {
content: String
optimizedContent: String
dataURI: String
absolutePath: String
relativePath: String
}
`)
}
async function parseSVG({
source,
url,
store,
cache,
createNode,
createNodeId,
}) {
const { absolutePath } = await createRemoteFileNode({
url,
parentNodeId: source.id,
store,
cache,
createNode,
createNodeId,
})
const svg = await fs.readFile(absolutePath, "utf8")
if (!svg) throw new Error("Unable to read " + source.id + ": " + absolutePath)
if (svg.includes("base64"))
console.log(
"SVG contains bitmap data; this data will be removed.",
source.id
)
const { data: optimizedSVG } = await svgo.optimize(svg)
return {
content: optimizedSVG,
originalContent: svg,
}
}
exports.createResolvers = ({
actions,
cache,
createNodeId,
createResolvers,
store,
reporter,
}) => {
const { createNode } = actions
createResolvers({
SanityImageAsset: {
svg: {
type: `InlineSvg`,
resolve: async source => {
const { url, mimeType } = source
if (mimeType !== "image/svg+xml" || !url) return null
const cacheId =
"sanity-svg-content-" +
crypto
.createHash(`md5`)
.update(url)
.digest(`hex`)
const result = await queue.add(async () => {
try {
const cachedData = await cache.get(cacheId)
if (cachedData) return cachedData
const result = await parseSVG({
source,
url,
store,
cache,
createNode,
createNodeId,
})
await cache.set(cacheId, result)
return result
} catch (err) {
console.error(err, source.id)
return null
}
})
return result
},
},
},
})
}
{
"name": "sanity-inline-svgs"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment