vite builds correctly inlined svg resources

Original link: https://blog.rxliuli.com/p/9eb3b1a6e46a4777b3661ce0bb890d69/

Scenes

At present, there is a bug in the function of inline media resources when vite is built. There has been a github issue since the end of 2020. I feel that it is unlikely to be solved in the short term, so I decided to use a plug-in to restore this function by myself.

Below is a dist built with vite, you can see that the svg is not correctly inlined into the code, but is split into a bundle separately, and the jpg image is correctly inlined.

1653919149233

Existing plugin

Why not use the plugin @rollup/plugin-image

  • It doesn’t do special processing for vite, vite’s built-in plug-in handles svg earlier than it does, it will never have a chance to process images
  • It does not handle resources from other modules in the monorepo project

It is not difficult to implement. The core is to intercept the load of .svg and replace it with a js file, which exports the svg dataUri string by default.

 import { createFilter , FilterPattern } from "@rollup/pluginutils" ; import { readFile } from "fs-extra" ; import svgToMiniDataURI from "mini-svg-data-uri" ; import * as path from "path" ; import { optimize , OptimizedSvg } from "svgo" ; import { Plugin } from "vite" ; const defaults = { exclude : null , include : null , } ; export function svgPatch ( opts ? : { include ? : FilterPattern ; exclude ? : FilterPattern ; } ) : Plugin { const options = Object . assign ( { } , defaults , opts ) ; const filter = createFilter ( options . include , options . exclude ) ; return { name : "vite-plugin-svg-patch" , enforce : "pre" , resolveId ( id : string , importer : string ) { if ( this . meta . watchMode ) { return null ; } if ( id . endsWith ( ".svg" ) ) { return path . resolve ( path . dirname ( importer ) , id ) ; } } , async load ( id ) { if ( this . meta . watchMode ) { return null ; } if ( ! filter ( id ) || ! id . endsWith ( ".svg" ) ) { return null ; } const source = optimize ( ( await readFile ( id , "utf-8" ) ) . replace ( / [\r\n]+ / gm , "" ) ) ; if ( source . error || source . modernError ) { console . error ( "svg optimization failed: " , id ) ; } const dataUri = svgToMiniDataURI ( ( source as OptimizedSvg ) . data ) ; return ` export default " ${ dataUri } "; ` ; } , } ; } 

use

Published as npm package @liuli-util/vite-plugin-svg-patch

 import { defineConfig } from "vite" ; import vue from "@vitejs/plugin-vue" ; import { svgPatch } from "@liuli-util/vite-plugin-svg-patch" ; export default defineConfig ( { plugins : [ vue ( ) , svgPatch ( ) ] , } ) ; 

The following is after using the plugin, you can see that the svg file is not divided into a separate file.

1653919908486

limitation

At present, I haven’t found a hook to process image resources using background-image: url("") in vue style/css files. It may be a hook that can only be accessed inside vite.

One idea is to use transformHook, but I don’t want to deal with things like sourcemap for the time being, so I haven’t tried it yet.

This article is reproduced from: https://blog.rxliuli.com/p/9eb3b1a6e46a4777b3661ce0bb890d69/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment