Roots Discourse

Loading SVG as data URI breaks on `yarn run build:production`

sage9

#1

I am embedding SVG images in CSS with with data:image/svg+xml scheme in order to reduce HTTP requests.

.youtube a {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 9.333l5.333 2.662-5.333 2.672v-5.334zm14-9.333v24h-24v-24h24zm-4 12c-.02-4.123-.323-5.7-2.923-5.877-2.403-.164-7.754-.163-10.153 0-2.598.177-2.904 1.747-2.924 5.877.02 4.123.323 5.7 2.923 5.877 2.399.163 7.75.164 10.153 0 2.598-.177 2.904-1.747 2.924-5.877z" fill="#ffffff"/></svg>');        
}

Running yarn run build works perfectly, however yarn run build:production produces this error:

    [14] (webpack)/buildin/global.js 509 bytes {0} [built]

    WARNING in  <theme_dir>/~/css-loader?-sourceMap!<theme_dir>/~/postcss-loader!<theme_dir>/~/resolve-url-loader?-sourceMap!<theme_dir>/~/sass-loader/lib/loader.js?-sourceMap!./styles/main.scss
    (Emitted value instead of an instance of Error)   resolve-url-loader cannot operate: CSS error
      <theme_dir>/resources/assets/styles/main.scss:6:218868: property missing ':'
      at error (<theme_dir>/epicenter/node_modules/css/lib/parse/index.js:62:15)

#2

I’m using postcss-inline-svg (along with svg-spritemap-webpack-plugin) in webpack.config.js:

line 6:
const postcssInlineSvg = require('postcss-inline-svg');

line 143:
postcss: [ autoprefixer({ browsers: config.browsers }), postcssInlineSvg(), ],

Clearly you have to yarn add postcss-inline-svg and in your SCSS you can then write:
.youtube a { background-image: svg-load('../images/svg/youtube-bg.svg'); }

In this way you can freely update the SVG without having to convert it each time.


#3

looks like you know what you’re talking about. I have the same issue with the actual released sage (and many more → Sage 9 - yarn run build:production - No errors, but missing CSS / https://github.com/roots/sage/issues/2017#issuecomment-361054297)

Maybe you already have a solution for this?

Because the actual webpack.config.js changed a lot since you describe your solution.

Thx


#4

I’ve been dealing with this issue today as well. It looks like SVGO is the culprit, it runs as part of cssnano and ImageminPlugin and breaks SVGs placed as background-images with a data:uri in (S)CSS.

As an example:

background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><defs><pattern id="pinstripe" patternUnits="userSpaceOnUse" width="8" height="8" patternTransform="rotate(-45)"><line x1="4" y="0" x2="4" y2="8" stroke="#{$brand-primary}" stroke-width="2" /></pattern></defs><rect width="100%" height="100%" fill="url(#pinstripe)" /></svg>');

Probably one of the default SVGO plugins is interfering, as I have had the problem with my SVG sprites as well (breaking them or causing display issues).

I’ve looked into the default SVGO plugin set and tried to disable them one by one, but in the end decided to disable SVGO all together, this makes both my sprites and inline SVG work again, but you miss out on any optimisations.

My webpack.config.optimize.js looks like this to make SVG sprites behave as expected:

'use strict'; // eslint-disable-line

const { default: ImageminPlugin } = require('imagemin-webpack-plugin');
const imageminMozjpeg = require('imagemin-mozjpeg');

const config = require('./config');

module.exports = {
  plugins: [
    new ImageminPlugin({
      optipng: { optimizationLevel: 7 },
      gifsicle: { optimizationLevel: 3 },
      pngquant: { quality: '65-90', speed: 4 },
      svgo: null,
      plugins: [imageminMozjpeg({ quality: 75 })],
      disable: (config.enabled.watcher),
    }),
  ],
};

And postcss.config.js to avoid the stripping of inline SVGs in (S)CSS:

/* eslint-disable */

const cssnanoConfig = {
  preset: ['default', { discardComments: { removeAll: true }, svgo: false }]
};

module.exports = ({ file, options }) => {
  return {
    parser: options.enabled.optimize ? 'postcss-safe-parser' : undefined,
    plugins: {
      cssnano: options.enabled.optimize ? cssnanoConfig : false,
      autoprefixer: true,
    },
  };
};