關於靜態資源打包後的相對路徑問題

將多個靜態資源打包爲單個資源以減小請求數目,是提升頁面加載速度的經常使用手段。因而上個星期,我就在實現網站靜態資源的自動打包功能,原覺得是個比較簡單的問題,實現起來也沒有遇到什麼障礙,不過在開發完畢投入使用的時候卻讓我跌了下眼鏡。因爲靜態資源在打包之後,它們的訪問路徑勢必會改變,這樣其餘一些依賴於原有路徑的資源就訪問不到了。這方面最多見的例子,即是CSS樣式表中引用的圖片路徑是相對於CSS文件路徑的。當意識到這個問題之後,還真是讓人手忙腳亂了一把。css

例如,有一個描述對話框組件的CSS文件,它的原有訪問路徑爲/styles/dialog/core.css,其中有行樣式表爲url(header.png),這意味這幅圖片的訪問路徑爲/styles/dialog/header.png。一樣,在另外一個文件/styles/menu/core.css中也有url(bg.png)這樣的代碼。那麼好,若是咱們將這兩個文件打包在一塊兒,叫作/packed/styles/dialog-menu.css,那麼瀏覽器就會去加載/packed/styles下的header.png和bg.png,爲何?由於url(…)這段代碼,在打包後出現的位置就不一樣了。html

解決這個問題彷佛有多種辦法,例如將資源文件複製到/packed/styles下面,但這就要處理文件重名的問題。若是使用組件化開發的方式,兩個組件之間應該不去考慮資源的重名,不然就產生了依賴。另外一種方式,是在CSS內部使用絕對路徑,例如在/styles/menu/core.css中使用url(/styles/menu/bg.png)而不是url(bg.png)。這麼作能夠解決打包上的問題,可是卻破壞了組件化的開發方式。例如此時dialog組件就不是獨立的了,它的圖片路徑是死的。而在理想狀況下,一個組件的CSS文件和圖片等資源應該是統一的,並獨立與其餘條件,這也是CSS中url(…)含義的設計目的。前端

固然,我並非說這種「組件化」的實踐是必須遵照的,若是隻是在開發一個獨立的項目,即可以將「絕對路徑」做爲項目中的約定。可是在實際狀況下,這種組件化及相對路徑的使用是客觀存在的。例如jQuery成百上千的插件,它們的CSS樣式中必定不會使用絕對路徑。那麼咱們又該如何對它進行打包呢?正則表達式

其實路徑問題也很容易解決,只要在「打包」的時候修改掉CSS文件內容裏的路徑便可。例如咱們能夠知道,若是瀏覽器是在/packed/styles/dialog-menu.css文件中,訪問到本來在/styles/dialog/core.css裏的內容,那麼本來的url(bg.png)就必須改寫成url(/styles/dialog/bg.png)這樣的絕對路徑,或者是url(../…/styles/dialog/bg.png)這樣相對於新地址的「相對路徑」。瀏覽器

這樣的修改其實並不複雜,例如在CSS中,彷佛須要替換的也只有url(…)這樣的地址了,一個普通的正則表達式即可以解決,而比較麻煩的多是JavaScript文件了。在某些組件化的JavaScript中,它須要的一些資源也是根據腳本文件的地址相對計算出來的。此時,其中的路徑可能只是一些普通的字符串而已,沒有規律保險的替換規則。若是要解決這個問題,咱們能夠在項目中造成某種約定,例如,計算相對路徑時都不是簡單的字符串拼接,而是使用一個函數調用。而這個函數調用,在進行「打包」時即可以看做是一個待替換的標誌。函數

相對路徑的問題彷佛就這麼解決了,我想前面這段描述也已經足夠清楚,比寫代碼還要清楚,因此暫時就先不提供我在項目裏使用的動態打包機制了。不過這裏還有個小小的花絮能夠一談。工具

負責前端開發的同事很重視靜態資源的打包問題,所以也就一直催促我實現這方面的功能。以前他說,他須要一個工具,輸入一個配置文件,即可以將指定文件打包,而後在正式站點發布時修改頁面上引用的地址就好了。我說這樣不行,會死人的。例如,一個組件會在多個頁面上使用,那麼它的更新會致使屢次打包,還要修改多個頁面文件,這對於站點的快速升級更新也是一個災難。此外,在頁面上所使用的靜態資源信息,還須要在打包工具的配置文件中重複,這也是一種違反DRY的狀況組件化

我理想中的打包機制要有如下幾個條件:性能

  • 遵照DRY原則,例如,一張頁面須要加載哪些腳本,此類信息只會出如今對應頁面中。
  • 在開發系統和生產系統上部署同一套代碼,而不會爲了生產系統修改代碼。
  • 自動打包,自動版本升級或回退。打包結果易於開發人員進行識別、分析及調試。
  • 簡單,清晰,性能高。

上週實現的解決方案彷佛基本符合這些條件,有機會我再來分享吧。網站

相關文章
相關標籤/搜索