@@ -371,7 +371,8 @@ async function fileToBuiltUrl(
371371 let url : string
372372 if (
373373 config . build . lib ||
374- ( ! file . endsWith ( '.svg' ) &&
374+ // Don't inline SVG with fragments, as they are meant to be reused
375+ ( ! ( file . endsWith ( '.svg' ) && id . includes ( '#' ) ) &&
375376 ! file . endsWith ( '.html' ) &&
376377 content . length < Number ( config . build . assetsInlineLimit ) &&
377378 ! isGitLfsPlaceholder ( content ) )
@@ -382,9 +383,13 @@ async function fileToBuiltUrl(
382383 )
383384 }
384385
385- const mimeType = mrmime . lookup ( file ) ?? 'application/octet-stream'
386- // base64 inlined as a string
387- url = `data:${ mimeType } ;base64,${ content . toString ( 'base64' ) } `
386+ if ( file . endsWith ( '.svg' ) ) {
387+ url = svgToDataURL ( content )
388+ } else {
389+ const mimeType = mrmime . lookup ( file ) ?? 'application/octet-stream'
390+ // base64 inlined as a string
391+ url = `data:${ mimeType } ;base64,${ content . toString ( 'base64' ) } `
392+ }
388393 } else {
389394 // emit as asset
390395 const { search, hash } = parseUrl ( id )
@@ -428,3 +433,28 @@ export async function urlToBuiltUrl(
428433 true ,
429434 )
430435}
436+
437+ // Inspired by https://github.com/iconify/iconify/blob/main/packages/utils/src/svg/url.ts
438+ function svgToDataURL ( content : Buffer ) : string {
439+ const stringContent = content . toString ( )
440+ // If the SVG contains some text, any transformation is unsafe, and given that double quotes would then
441+ // need to be escaped, the gain to use a data URI would be ridiculous if not negative
442+ if ( stringContent . includes ( '<text' ) ) {
443+ return `data:image/svg+xml;base64,${ content . toString ( 'base64' ) } `
444+ } else {
445+ return (
446+ 'data:image/svg+xml,' +
447+ stringContent
448+ . trim ( )
449+ . replaceAll ( '"' , "'" )
450+ . replaceAll ( '%' , '%25' )
451+ . replaceAll ( '#' , '%23' )
452+ . replaceAll ( '<' , '%3c' )
453+ . replaceAll ( '>' , '%3e' )
454+ // Spaces are not valid in srcset it has some use cases
455+ // it can make the uncompressed URI slightly higher than base64, but will compress way better
456+ // https://github.com/vitejs/vite/pull/14643#issuecomment-1766288673
457+ . replaceAll ( / \s + / g, '%20' )
458+ )
459+ }
460+ }
0 commit comments