本文最后更新于:2022年5月30日 下午
场景
目前 vite 构建时内联媒体资源的功能有 bug,从 2020 年底就已经存在一个 github issue,感觉短期不太可能解决,于是吾辈决定自行使用插件恢复这个功能。
下面是一个使用 vite 构建的 dist,可以看到其中的 svg 并未被正确内联到代码中,而是单独分割为了一个 bundle,而 jpg 图片则被正确内联。
现有插件
为什么不使用插件 @rollup/plugin-image
- 它没有对 vite 做特殊处理,vite 本身内置插件处理 svg 的时机要早于它,它永远不会有机会处理图片
- 它没有处理 monorepo 项目中其他模块的资源
实现起来并不困难,核心是拦截 .svg 的 load,将之替换为一个 js 文件,其中默认导出 svg dataUri 字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 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}";` }, } }
|
使用
已发布为 npm 包 @liuli-util/vite-plugin-svg-patch
1 2 3 4 5 6 7
| 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()], })
|
以下是使用插件之后,可以看到 svg 文件没有被单独分割为一个文件了。
局限性
目前,没有找到一种钩子去处理 vue style/css
文件中使用 background-image: url("")
的图片资源,可能是只有 vite 内部才可以访问的钩子吧
一种思路是使用 transformHook,但吾辈暂时不想处理 sourcemap 之类的事情,所以暂未尝试。