JetBrains / svg-sprite-loader

Webpack loader for creating SVG sprites.
MIT License
2.02k stars 272 forks source link

SVG not rendered properly #380

Closed burnmaniac closed 4 years ago

burnmaniac commented 4 years ago

Do you want to request a feature, report a bug or ask a question? Report a bug.

What is the current behavior? SVG is not rendered properly.

What is the expected behavior? SVG should be rendered properly.

image

Original SVG:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="234" height="74" viewBox="0 0 234 74">
    <defs>
        <linearGradient id="a" x1="50%" x2="48.864%" y1="48.434%" y2="51.159%">
            <stop offset="0%" stop-color="#0080FF" stop-opacity=".5"/>
            <stop offset="100%" stop-color="#0080FF" stop-opacity="0"/>
        </linearGradient>
        <linearGradient id="d" x1="100%" x2="0%" y1="50%" y2="50%">
            <stop offset="0%" stop-color="#404752"/>
            <stop offset="85.856%" stop-color="#0080FF"/>
            <stop offset="100%" stop-color="#0080FF"/>
        </linearGradient>
        <path id="c" d="M43 17h10.694C73.625 17 89.181 37 113 37"/>
        <filter id="b" width="157.1%" height="300%" x="-28.6%" y="-100%" filterUnits="objectBoundingBox">
            <feMorphology in="SourceAlpha" operator="dilate" radius="2" result="shadowSpreadOuter1"/>
            <feOffset in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
            <feMorphology in="SourceAlpha" radius="2" result="shadowInner"/>
            <feOffset in="shadowInner" result="shadowInner"/>
            <feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out" result="shadowOffsetOuter1"/>
            <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="6"/>
            <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0.501960784 0 0 0 0 1 0 0 0 1 0"/>
        </filter>
        <path id="e" d="M3.549 13.222l-2.771-2.77L7.059 4.16H2.178V.778h11.044v11.044H9.85V6.941z"/>
        <path id="h" d="M120 37h5.132a30 30 0 0 0 9.487-1.54l2.881-.96a23.717 23.717 0 0 1 15 0l13.013 4.338a30 30 0 0 0 18.974 0L197.5 34.5a23.717 23.717 0 0 1 15 0l2.881.96a30 30 0 0 0 9.487 1.54H230"/>
        <filter id="g" width="136.4%" height="470.9%" x="-18.2%" y="-187.2%" filterUnits="objectBoundingBox">
            <feMorphology in="SourceAlpha" operator="dilate" radius="2" result="shadowSpreadOuter1"/>
            <feOffset in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
            <feMorphology in="SourceAlpha" radius="2" result="shadowInner"/>
            <feOffset in="shadowInner" result="shadowInner"/>
            <feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out" result="shadowOffsetOuter1"/>
            <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="6"/>
            <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0.454901961 0 0 0 0 0.498039216 0 0 0 0 0.533333333 0 0 0 1 0"/>
        </filter>
    </defs>
    <g fill="none" fill-rule="evenodd">
        <path fill="url(#a)" d="M0 19h53.694C73.625 19 89.181 39 113 39L2.867 34.127A3 3 0 0 1 0 31.13V19z"/>
        <g stroke-linecap="round">
            <use fill="#000" filter="url(#b)" xlink:href="#c"/>
            <use stroke="url(#d)" stroke-width="4" xlink:href="#c"/>
        </g>
        <path fill="#0080FF" d="M32.284 0H3a3 3 0 0 0-3 3v28a3 3 0 0 0 3 3h29.284a3 3 0 0 0 2.586-1.479l8.235-14a3 3 0 0 0 0-3.042l-8.235-14A3 3 0 0 0 32.284 0z"/>
        <g transform="translate(12 10)">
            <mask id="f" fill="#fff">
                <use xlink:href="#e"/>
            </mask>
            <use fill="#000" fill-rule="nonzero" xlink:href="#e"/>
            <g fill="#FFF" fill-rule="nonzero" mask="url(#f)">
                <path d="M-1-1h16v16H-1z"/>
            </g>
        </g>
        <g stroke-dasharray="0,8" stroke-linecap="round">
            <use fill="#000" filter="url(#g)" xlink:href="#h"/>
            <use stroke="#404752" stroke-width="4" xlink:href="#h"/>
        </g>
    </g>
</svg>

Sprite, copied from Network tab in DevTools:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <style>
            .sprite-symbol-usage {display: none;}
            .sprite-symbol-usage:target {display: inline;}
        </style>
        <symbol viewBox="0 0 234 74" id="symbol-voiceLevelStartHigh">
            <defs>
                <path id="symbol-voiceLevelStartHigh_c" d="M43 17h10.694C73.625 17 89.181 37 113 37"/>
                <path id="symbol-voiceLevelStartHigh_e"
                      d="M3.549 13.222l-2.771-2.77L7.059 4.16H2.178V.778h11.044v11.044H9.85V6.941z"/>
                <path id="symbol-voiceLevelStartHigh_h"
                      d="M120 37h5.132a30 30 0 009.487-1.54l2.881-.96a23.717 23.717 0 0115 0l13.013 4.338a30 30 0 0018.974 0L197.5 34.5a23.717 23.717 0 0115 0l2.881.96a30 30 0 009.487 1.54H230"/>
                <filter id="symbol-voiceLevelStartHigh_b" width="157.1%" height="300%" x="-28.6%" y="-100%"
                        filterUnits="objectBoundingBox">
                    <feMorphology in="SourceAlpha" operator="dilate" radius="2"
                                  result="shadowSpreadOuter1"></feMorphology>
                    <feOffset in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
                    <feMorphology in="SourceAlpha" radius="2" result="shadowInner"></feMorphology>
                    <feOffset in="shadowInner" result="shadowInner"></feOffset>
                    <feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out"
                                 result="shadowOffsetOuter1"></feComposite>
                    <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="6"></feGaussianBlur>
                    <feColorMatrix in="shadowBlurOuter1"
                                   values="0 0 0 0 0 0 0 0 0 0.501960784 0 0 0 0 1 0 0 0 1 0"></feColorMatrix>
                </filter>
                <filter id="symbol-voiceLevelStartHigh_g" width="136.4%" height="470.9%" x="-18.2%" y="-187.2%"
                        filterUnits="objectBoundingBox">
                    <feMorphology in="SourceAlpha" operator="dilate" radius="2"
                                  result="shadowSpreadOuter1"></feMorphology>
                    <feOffset in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
                    <feMorphology in="SourceAlpha" radius="2" result="shadowInner"></feMorphology>
                    <feOffset in="shadowInner" result="shadowInner"></feOffset>
                    <feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out"
                                 result="shadowOffsetOuter1"></feComposite>
                    <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="6"></feGaussianBlur>
                    <feColorMatrix in="shadowBlurOuter1"
                                   values="0 0 0 0 0.454901961 0 0 0 0 0.498039216 0 0 0 0 0.533333333 0 0 0 1 0"></feColorMatrix>
                </filter>
            </defs>
            <g fill="none" fill-rule="evenodd">
                <path fill="url(#symbol-voiceLevelStartHigh_a)"
                      d="M0 19h53.694C73.625 19 89.181 39 113 39L2.867 34.127A3 3 0 010 31.13V19z"/>
                <g stroke-linecap="round">
                    <use fill="#000" filter="url(#symbol-voiceLevelStartHigh_b)"
                         xlink:href="#symbol-voiceLevelStartHigh_c"/>
                    <use stroke="url(#symbol-voiceLevelStartHigh_d)" stroke-width="4"
                         xlink:href="#symbol-voiceLevelStartHigh_c"/>
                </g>
                <path fill="#0080FF"
                      d="M32.284 0H3a3 3 0 00-3 3v28a3 3 0 003 3h29.284a3 3 0 002.586-1.479l8.235-14a3 3 0 000-3.042l-8.235-14A3 3 0 0032.284 0z"/>
                <g transform="translate(12 10)">
                    <use fill="#000" fill-rule="nonzero" xlink:href="#symbol-voiceLevelStartHigh_e"/>
                    <g fill="#FFF" fill-rule="nonzero" mask="url(#symbol-voiceLevelStartHigh_f)">
                        <path d="M-1-1h16v16H-1z"/>
                    </g>
                </g>
                <g stroke-dasharray="0,8" stroke-linecap="round">
                    <use fill="#000" filter="url(#symbol-voiceLevelStartHigh_g)"
                         xlink:href="#symbol-voiceLevelStartHigh_h"/>
                    <use stroke="#404752" stroke-width="4" xlink:href="#symbol-voiceLevelStartHigh_h"/>
                </g>
            </g>
        </symbol>
        <linearGradient id="symbol-voiceLevelStartHigh_a" x1="50%" x2="48.864%" y1="48.434%" y2="51.159%">
            <stop offset="0%" stop-color="#0080FF" stop-opacity=".5"/>
            <stop offset="100%" stop-color="#0080FF" stop-opacity="0"/>
        </linearGradient>
        <linearGradient id="symbol-voiceLevelStartHigh_d" x1="100%" x2="0%" y1="50%" y2="50%">
            <stop offset="0%" stop-color="#404752"/>
            <stop offset="85.856%" stop-color="#0080FF"/>
            <stop offset="100%" stop-color="#0080FF"/>
        </linearGradient>
        <mask id="symbol-voiceLevelStartHigh_f" fill="#fff">
            <use xlink:href="#symbol-voiceLevelStartHigh_e"/>
        </mask>
    </defs>
    <use id="symbol-voiceLevelStartHigh-usage" xlink:href="#symbol-voiceLevelStartHigh" class="sprite-symbol-usage"/>
</svg>

package.json

{
  "main": "index.js",
  "engines": {
    "node": ">=8"
  },
  "devDependencies": {
    "@babel/core": "^7.6.2",
    "@babel/runtime-corejs3": "^7.6.2",
    "@hot-loader/react-dom": "^16.9.0",
    "autoprefixer": "^9.6.4",
    "babel-core": "^7.0.0-bridge.0",
    "babel-eslint": "^10.0.3",
    "babel-jest": "^24.9.0",
    "babel-loader": "^8.0.5",
    "case-sensitive-paths-webpack-plugin": "^2.2.0",
    "chalk": "^2.4.2",
    "connect-history-api-fallback": "^1.6.0",
    "core-js": "^3.2.1",
    "css-loader": "^2.1.1",
    "cssnano": "^4.1.10",
    "dotenv": "^8.1.0",
    "dotenv-expand": "^5.1.0",
    "enzyme": "^3.9.0",
    "enzyme-adapter-react-16": "^1.12.1",
    "eslint": "^5.16.0",
    "eslint-loader": "^2.1.2",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-react": "^7.16.0",
    "eslint-plugin-react-hooks": "^1.7.0",
    "express": "^4.16.4",
    "file-loader": "^3.0.1",
    "fs-extra": "^7.0.1",
    "html-webpack-plugin": "^3.2.0",
    "isomorphic-fetch": "^2.2.1",
    "jest": "^24.9.0",
    "mini-css-extract-plugin": "^0.6.0",
    "node-sass": "^4.13.0",
    "nodemon": "^1.19.3",
    "object-assign": "^4.1.1",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-flexbugs-fixes": "^4.1.0",
    "postcss-loader": "^3.0.0",
    "promise": "^8.0.3",
    "raf": "^3.4.1",
    "regenerator-runtime": "^0.13.2",
    "require-from-string": "^2.0.2",
    "resolve-url-loader": "^3.1.0",
    "sass-loader": "^7.3.1",
    "style-loader": "^0.23.1",
    "stylelint": "^9.10.1",
    "stylelint-scss": "^3.11.1",
    "stylelint-selector-bem-pattern": "^2.1.0",
    "stylelint-webpack-plugin": "^0.10.5",
    "svg-sprite-loader": "^3.8.0",
    "svg-transform-loader": "^2.0.7",
    "svg-url-loader": "^2.3.2",
    "svgo": "^1.2.1",
    "svgo-loader": "^2.2.0",
    "svgxuse": "^1.2.6",
    "sw-precache-webpack-plugin": "^0.11.5",
    "terser-webpack-plugin": "^1.4.1",
    "url-loader": "^1.1.2",
    "url-search-params-polyfill": "^5.1.0",
    "webpack": "^4.41.0",
    "webpack-dev-middleware": "^3.7.2",
    "webpack-hot-middleware": "^2.24.3",
    "webpack-manifest-plugin": "^2.2.0",
    "yargs": "^13.2.2"
  },
  "dependencies": {
    "axios": "^0.19.0",
    "classnames": "^2.2.6",
    "connected-react-router": "^6.5.2",
    "history": "^4.10.1",
    "immutable": "^4.0.0-rc.12",
    "include-media": "^1.4.9",
    "lodash.debounce": "^4.0.8",
    "moment": "^2.24.0",
    "normalize.css": "^8.0.1",
    "prop-types": "^15.7.2",
    "query-string": "^6.8.3",
    "rc-slider": "^8.7.1",
    "react": "^16.10.2",
    "react-circular-progressbar": "^2.0.2",
    "react-datepicker": "^2.9.6",
    "react-dom": "^16.10.2",
    "react-hot-loader": "^4.12.15",
    "react-redux": "^7.1.1",
    "react-router": "^5.1.2",
    "react-router-config": "^5.1.1",
    "react-select": "^3.0.8",
    "react-smooth-collapse": "^2.1.0",
    "react-switch": "^5.0.1",
    "react-tabs": "^3.0.0",
    "react-transition-group": "^4.3.0",
    "recompose": "^0.30.0",
    "redux": "^4.0.4",
    "redux-devtools-extension": "^2.13.8",
    "redux-logger": "^3.0.6",
    "redux-saga": "^1.1.1",
    "reselect": "^4.0.0",
    "roboto-fontface": "^0.10.0"
  },
  "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom"
  },
  "browserslist": [
    "last 2 Chrome versions"
  ]
}

SVG is rendered using SVGSpriteSymbol component which looks like this:

import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';

export default class SVGSpriteSymbol extends PureComponent {
    static propTypes = {
        className: PropTypes.string,
        spriteSymbol: PropTypes.object.isRequired,
    };

    static defaultProps = {
        className: '',
    };

    render() {
        const {className, spriteSymbol, ...restProps} = this.props;
        return (
            <svg viewBox={spriteSymbol.viewBox} className={className} {...restProps}>
                <use xlinkHref={spriteSymbol.url} />
            </svg>
        );
    }
}

Part of webpack config:

{
    test: [/\.svg$/],
    issuer: /\.(js|jsx|mjs)$/,
    use: [
        {
            loader: require.resolve('svg-sprite-loader'),
            options: {
                symbolId: 'symbol-[name]',
                extract: true,
                spriteFilename: 'media/sprite.[hash:8].svg',
                esModule: false,
            },
        },
        require.resolve('svgo-loader'),
    ],
},

Plugin is just instantiated as new SpriteLoaderPlugin() without any additional options.

Please tell us about your environment:

Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc) I had suspicion that the issue lies somewhere in React. As React is doing some mapping until the SVG gets into DOM, I thought that something is not mapped properly. So, I opened the issue in their repo (https://github.com/facebook/react/issues/17645). However, after some time, we are 99% sure that this has nothing to do with React. It's either svg-sprite-loader or something else.

Since this is my first issue here, sorry if I didn't provide enough info. I'm willing to add additional information in case it's needed, just let me know what do you need. Thank you.

kisenka commented 4 years ago

Could you please create repo with minimal setup to demonstrate a problem (package.json, webpack config, SVG image and piece of your code). If you don't want to create a repository - you can create a gist with multiple files.

burnmaniac commented 4 years ago

Sorry, I've been busy. I'll create the repo soon.

shayan-binary-2 commented 4 years ago

@kisenka I've create a sample repo here https://github.com/shayan-binary-2/svg-sprite-loader-sample I have same problem.

kisenka commented 4 years ago

@burnmaniac please see this comment

burnmaniac commented 4 years ago

Thanks! That's what we did at the end. We didn't have to use extract-svg-sprite-webpack-plugin, it just magically works when SVG is referenced in CSS.

Sorry for not creating the repo, the things are super crazy at the moment.

Thank you very much for your time and help! Issue closed!