新聞中心
大家好,我是前端西瓜哥。

誒喲喂,SVG 怎么沒內(nèi)嵌?
最近啊,西瓜哥我用 vite 去給一個項(xiàng)目構(gòu)建(vite build)一個應(yīng)用。打包結(jié)果是一個 html 和一些加了哈希的資源。
然后打包出來的文件一看,發(fā)現(xiàn)居然有好幾個 1 Kb 以下的 SVG 文件。
我搜了下源碼,這些 SVG 是這樣被使用的:

不對呀,理論上小于 4 Kb 的靜態(tài)資源,是會轉(zhuǎn)成 base64 編碼字符串,嵌入到其他資源中。
較小的資源體積小于 assetsInlineLimit 選項(xiàng)值 則會被內(nèi)聯(lián)為 base64 data URL。
build.assetsInlineLimit 默認(rèn)值為 4096 (4kb)。
我發(fā)現(xiàn)使用庫模式(打包成 index.es.js,使用該模式需要設(shè)置 build.lib 配置)時,是不會出現(xiàn) SVG 文件的。
如果你指定了 build.lib,那么 build.assetsInlineLimit 將被忽略,無論文件大小或是否為 Git LFS 占位符,資源都會被內(nèi)聯(lián)。
所以一開始我以為我的配置設(shè)置的有問題,因?yàn)閹炷J經(jīng)]問題了。
我折騰了大半天,檢查配置,查文檔,assetsInlineLimit 給你加到 999999,安裝其他版本的包,給引入的文件末尾加上 ?inline。各種嘗試,都沒用。
后來我用最新版的 vite 構(gòu)建了一個新的 Vue 項(xiàng)目。
發(fā)現(xiàn)它這個官方給的 demo 打包出來的文件 SVG 都沒做內(nèi)聯(lián)。
好家伙,我尋思 vite 本身就不支持 SVG 轉(zhuǎn) base64 編碼內(nèi)嵌。
設(shè)計(jì)如此,本就不支持 SVG 轉(zhuǎn) Base64
走,去翻翻 vite 的 issue,然后找到了一個 3 年前的 issue,編號 1204。
這個 issue 標(biāo)記為 enhancement,即它是一個增強(qiáng)功能,并不是 bug。
此外可以看到有兩個 PR 是要解決這個 issue 的。
一個 PR 被關(guān)閉了,一個 PR 是打開著。我們?nèi)タ纯础?/p>
先看看被關(guān)閉的那個,PR 編號是 1716,是 vite 成員提的 PR。
他說他不贊成 SVG 轉(zhuǎn)成 Base64 嵌入到 HTML,SVG 是個文本類的特殊圖片格式,不是二進(jìn)制,沒必要再轉(zhuǎn)一層 Base64,導(dǎo)致體積變大。
因?yàn)?Base64 需要用 4 個字符表達(dá)原來文本的 3 個字節(jié),會增大 33~36% 的體積。
即希望結(jié)果是:

而不是:

雖然不打算轉(zhuǎn) Base64,但還是可以轉(zhuǎn) utf8 格式的 Data URL 的,一樣可以實(shí)現(xiàn)內(nèi)嵌的效果,而且體積更小,于是提了這個 PR。
這個 PR 是有問題的,有些情況沒處理,比如轉(zhuǎn)義,去掉 svg fragments 等。
然而過了一個月,這個 PR 還是沒進(jìn)展,說明 優(yōu)先級并不高。
此時一位路過的野生程序員說他來搭把手。
于是這個 PR 關(guān)閉了,這位老哥創(chuàng)建了一個新的 PR。
這個 PR 一直就掛在那
加油啊,路過的程序員老哥。你是我們?nèi)迦说南M ?/p>
看看 PR。
兩年前的 PR,至今仍是 Open 狀態(tài)。
哦豁,涼了。
發(fā)生甚么事了?我瞅瞅。
看下 PR 的內(nèi)容。引入了一個 mini-svg-data-uri 第三方包,來做 SVG 轉(zhuǎn) DataUrl,改了一些判斷條件,因?yàn)楹推胀ㄙY源直接走轉(zhuǎn) base64 不同,SVG 是要直接用原來的文本內(nèi)容的。改了了幾個測試用例。
看著不少 review 和討論,看著應(yīng)該還行,有幾個 vite 成員 approved 了。
最后時需要有人手動測試是否處理好了 SVG Segment 的情況。此時提 PR 的老哥不見了。
SVG Segment 是 SVG 的一個比較特殊的用法,大概是這樣(來自 MDN)。
對于一個 SVG,我們可以用 view 標(biāo)簽指定某種情況下特定的 viewBox 視口范圍。
然后在使用的時候通過 icon.svg#

效果:
回到 PR。
好久,后面有人幫著測試了,發(fā)現(xiàn)有問題。然后就,沒有然后了,此外還有因?yàn)殚L期沒合入出現(xiàn)的合并沖突。
湊合著用吧
啊這。
我 fork 了 vite 項(xiàng)目,把這位老哥的修改應(yīng)用到最新版本上,然后 build 了一下,并拿去構(gòu)建我的一個 demo 項(xiàng)目,結(jié)果 SVG 成功變成了 Base64。
然后我運(yùn)行測試相關(guān)的命令,各種不對。
因?yàn)橛行┰瓉磙D(zhuǎn)換為正常 url 的,現(xiàn)在會轉(zhuǎn)成 base64,就匹配不上了。我還發(fā)現(xiàn) css url 的邏輯還有點(diǎn)問題,拿到了一個錯誤的 none 值。
誒,感覺要提 PR 的話,要修正原來的測試用例,并補(bǔ)充一些新的測試用例,還要處理 css 的情況。行吧,以后再看看。
回到我一開始的需求,行,你不給我轉(zhuǎn) Base64 是吧?我通過 ?raw 直接拿到 SVG 文本內(nèi)容,給你動態(tài)轉(zhuǎn)成 Base64。
import iconSvg from './image/someIcon.svg?raw'; // 這個會拿到 ""
const toSVGDataUrl = (str: string) => {
const base64 = btoa(str);
return `data:image/svg+xml;base64,${base64}`;
};
![]()
還行(又不是不能用)。
結(jié)尾
這次經(jīng)歷,我認(rèn)識到 一個大型的開源項(xiàng)目的維護(hù)者,對單元測試是非??粗氐?,因?yàn)樗绊懼f萬的開發(fā)者,必須保證在絕大多數(shù)情況下能正確運(yùn)行。
突然想起之前 VSCode 我更新了最新版本,結(jié)果運(yùn)行一段時間就會報(bào)錯需要重啟。
然后就是 vite 維護(hù)者 非常注重性能,畢竟是一個很重要的構(gòu)建工具。SVG 是可以 Base64 的,實(shí)現(xiàn)邏輯也很簡單,和其他圖形走一樣的邏輯。
但 SVG 可以直接用原本的文本數(shù)據(jù),更小,有優(yōu)化空間。因?yàn)轶w積可以優(yōu)化,所以維護(hù)者就寧缺毋濫,寧可丟掉這個功能。
要是我,我可能就先圖省事,直接支持 Base64 了,然后有機(jī)會再優(yōu)化(通常不了了之)。
然后是優(yōu)先級,優(yōu)先級不高,維護(hù)者就是不會主動去實(shí)現(xiàn)。
此時就需要社區(qū)的力量了,如果你很需要某個功能,就要積極提 PR,積極討論并主動推進(jìn),否則可能像這個 PR 一樣,半途而廢。
文章題目:不是吧?強(qiáng)大的Vite居然不支持內(nèi)SVG轉(zhuǎn)Base64內(nèi)嵌?
鏈接地址:http://fisionsoft.com.cn/article/cocspje.html


咨詢
建站咨詢
