深入Liferay當頁面請求css資源利用parseSass()方法解析

餘二五發表於2017-11-14

前面已經用了幾篇文章詳細的講解了DynamicCSSFilter,現在我們來看他們是如何應用到載入css資原始檔的。


前提:

假定我們開發了一個theme叫platform-In-theme,它其中我們寫了一個main.css,並且在其中我們用@import url()語法包含了若干個其他css,其中有一個是forms.css,並且這個css是用Sass的語法規則寫的,我們來深入研究下載入這個2個css檔案的異同。


除錯分析:

首先,當頁面請求main.css的時候,因為它滿足DynamicCSSFilter的模式,所以進入processFilter()方法,由前面幾篇文章,很快的拿到requestURI,requestPath,contextPath等資訊,

162515346.png

從這圖上可以很清楚的看到,這個realPath是在我們的tomcat伺服器上的webapps目錄下的theme部署子目錄,所以說這個是正確的,我們的自定義theme都是部署在這個目錄上。


現在我們可以看下原始還沒有被解析的main.css長什麼樣子:

162732381.png

很顯然,和我們設想的一樣,它就是作為一個總的css用來包含其他的css檔案。


現在開始解析這個css 檔案,呼叫的是DynamicCSSUtil類的parseSass()方法.


首先它在第用98行利用theme=_getTheme(request,cssRealPath)來

獲取當前theme,因為我們的站點使用了platform-In-theme,所以返回這個theme.


163301993.png


然後,它利用_isThemeCssFastLoad(request,themeDisplay)方法獲取我們是否啟用了fast load ,因為這裡我們沒有啟用fast load,所以返回false.


然後在115行獲取cssRealFile的File物件,剛才講過了,這個theme在伺服器的webapps的相應theme目錄中。

163844457.png


然後呼叫SassToCssBuilder.getCacheFile(cssRealPath)方法

164948336.png

來獲取這個css資原始檔對應的快取檔案,它首先吧真實css資原始檔的反斜槓”\”全部替換成正斜槓”/”,然後獲取最後一個正斜槓位置,這是用來區分檔案路徑部分和檔名部分,然後它在中間插入.sass_cache.

(千萬注意,這次和上次說的$CATALINA_HOME/TMPDIR 下面的快取資料檔案完全不同,那個檔案是用於直接返回到客戶端(如果存在並且最新)的最終css檔案,如果使用那個檔案,就壓根不會呼叫parseSass()方法,而這個快取的是原始的css資原始檔,它是在parseSass()方法中被呼叫的,所以用途不同)


所以獲得的快取檔案的路徑就是如下圖:

164742519.png


這裡有個判斷,如果這個快取檔案存在並且是最新的,那麼就不用呼叫jRuby解析,而是直接把這個快取檔案的內容作為最終parseSass()的返回值,也就是作為最終解析完的普通css檔案輸出,但是我們是第一次,所以沒有這個資原始檔,只好老老實實走jRuby解析的過程。


(1)正式解析的第一步是呼叫SassToCssBuilder.parseStaticTokens(content)方法來吧一些靜態的符號替換掉:

165118567.png

很容易理解,就是把Sass中的一些特殊內容替換掉,比如文字的寬度,高度,和輸入框的高度寬度。

在這一步完結後,我們的main.css不受到影響。


(2)正式解析的第二步是先通過getQueryString方法獲得請求字串。

165650724.png

然後呼叫_propagateQueryString()方法進行操作:

165753961.png

這步驟的作用是對於每一個@import(url …)匯入的資原始檔,都在後面加上請求字串。所以在這一步之後,我們的main.css變為:

165924309.png

和我們設想的一樣,所有的@import url 的url後面都附加了請求字串。這是為了保證請求一致性(我猜的)


(3)正式解析的第三步就進入了jRuby解析引擎的核心了,這是通過_parseSass私有方法來完成的:

170129737.png

從這裡我們可以看出,它首先會構造一個HashMap物件,然後把我們要解析必要的引數,比如被解析的Sass內容(content),css的真實路徑(cssRealPath),在當前應用使用的Theme的css路徑(cssThemePath),sass的快取位置(sassCachePath)都放在HashMap中,然後在第295行使用_rubyExecutor.eval()方法呼叫jRuby解析器(位於/webapps/ROOT/WEB-INF/lib/jruby.jar中)來解析這個Sass檔案:

170516188.png


最後解析完的結果通過unsyncPrintWriter輸出而返回,對於我們的main.css來說,經過這一步之後,結果還是一樣的。因為這檔案大多數都是引入其他檔案,並沒有Sass的語法,所以不受到jRuby解析引擎的 影響。


(4)正式解析的第四步是吧@portal_ctx@和@theme_image_path@註解都替換成相應的字串,這個工作程式碼如下:

170804146.png

我們的main.css中沒有這些識別符號,所以不受到影響。


經過以上4步之後,這個方法就返回了dynamicContent,我們可以看到,它最終 返回到瀏覽器後的結果和正式解析第二步的一樣:

170957687.png



以上我們講解的是對於main.css的資源訪問,我們現在來看下對於其中包含的某個用Sass寫的檔案,比如說上面的forms.css,這個流程又是這麼樣的。


其實大體上流程都一致:

171222343.png

我這裡也想省略去多數重複的除錯流程了,反正最終不一樣的就是正式解析的第3步,它會去呼叫jruby.jar中的解析引擎去完成具體的解析,所以我們開始這個forms.css檔案的內容是:

171440365.png

解析完成之後,這個檔案內容變為:

171531240.png




總結:

(1)當單個載入Sass資原始檔的時候,這種Sass資原始檔都有可能有解析完的檔案快取在伺服器上,並且快取檔案的位置一定在原始資原始檔的上級目錄下的.sass_cache目錄下,並且檔名和原始Sass資原始檔名字相同。

(2)正式解析的第一步是解析Sass檔案中的靜態符號,比如@model_hints_contant….@

(3) 正式解析的第二步是吧所有Sass中的以@import url()形式給出的外部引入,其被引入的資原始檔後面都加上請求字串,這是為了保證其請求的一致性。

(4)正式解析的第三步是呼叫jRuby的解析引擎根據解析語法進行解析,它會吧所有的Sass語法替換為普通的css語法,這個解析引擎位於webapps/ROOT/WEB-INF/lib/jruby.jar jar包中

(5)正式解析的第四步是做一些收尾工作,吧一些靜態識別符號@portal_ctx@和@theme_image_path@解析為字串,因為在css檔案中經常會用到一些外部圖片參與到樣式中。

(6)對於main.css ,主要影響的是(3)

(7)對於main.css包含的某個css,如果它是用Sass語法寫的,那麼主要受到影響的是(4)

(8)一般的css,如果頁面上有一些特殊的記號,那麼受到(2)和 (5)影響。

本文轉自 charles_wang888 51CTO部落格,原文連結:http://blog.51cto.com/supercharles888/1283396,如需轉載請自行聯絡原作者


相關文章