2010年8月31日 星期二

ASP.NET對Javascript與CSS檔案進行壓縮


前一篇文章「壓縮網頁大小」是說明如何在網頁於輸出前進行檔案的GZip壓縮,

而現在要來說明如何去針對頁面中所使用的Javascript與CSS進行壓縮。


其實對Javascript與CSS的優化有很多種,使用YSlow或是PageSpeed對網頁進行分析,也會有特別針對這兩種檔案的建議。

YSlow的分析建議,抓出了很多未經過壓縮處理的js、css檔案…..抓出一個就會扣3分…

這個項目有這麼多個沒有進行處理,所以此項目只有F。

分析項目也會告訴你,進行壓縮處理能有什麼樣的好處,說明裡有強調如果進行壓縮會降低約70%的大小。

可以看到我的檔案的suffix都有個 compress或是compressed,

其實也不是經過GZip壓縮,而是利用YSlow所提供的工具連結,進行檔案的minify所以只是一個命名上的錯用。

image

工具中的連結,會導引你到網站中幫你網站所使用的js、css做些縮小化處理,

這邊也提供圖片的壓縮處理,它所壓縮過的檔案的確是會大大縮小你的圖片檔案大小,但卻不會對品質影響太大,相當值得推薦使用。

image


這邊告訴你使用YSlow提供的壓縮工具,可以節省多少的檔案大小。

image

PageSpeed也提出對於js、css檔案的壓縮建議。

PageSpeed也是有同樣的項目分析建議 ,並且也有提供最佳化的工具連結。

image

工具中的連結,會導引你到網站中幫你網站所使用的js、css做些縮小化處理,

PageSpeed也提供圖片的壓縮處理,它所壓縮過的檔案的確是會大大縮小你的圖片檔案大小,

卻不會對品質影響太大,相當值得推薦使用。

但是,上述的工具最多只提供你對js、css檔案做縮小化的功能,縮小化對於檔案大小的變化其實還是有限,

所以還是要用Gzip進行壓縮,才能達到我們要的目的,而網路上也有許多的工具可以幫助到我們處理這項工作,


進行壓縮前,看一下原本的檔案大小

image

看起來好像也沒有多少,但如果你的網站有一堆js、css檔案,然後每個都會有超過30KB以上,然後天天有成千上萬的人造訪…

其實想起來,對於網站的流量也算是個成本上的負擔,而且我的檔案還是經過最小化處理過。

圖中可以看到Server回應的Header內容,輸出的Javascript沒有做GZip處理

image 

當然我們也是可以利用IIS的設定,去針對這些靜態檔案做Gzip的壓縮處理,

例如:應用 IIS 6.0 的 Gzip 壓縮功能降低網路傳輸量,這篇文章就有相當清楚的說明。


但如果你所使用的主機環境不允許你去做這些設定的時候呢?
(虛擬主機、許多系統共用主機而不允許中斷行為、其他原因)
此時就使用程式的方式來解決這個問題。


一般網路上會找到一些相關的文章,有的會用HttpHandler或是HttpModule來進行,

用這兩種方式的好處是,你只要寫好程式然後再到Web.Config中的這兩個區段去增加設定即可,

不過我這邊要用的是在Global.asax中去做處理,方式就如同「壓縮網頁大小」中的方式一樣。

From MSDN:

Global.asax http://msdn.microsoft.com/zh-tw/library/2027ewzw(v=VS.80).aspx

Global.asax 檔案 (又稱為 ASP.NET 應用程式檔案) 是一種選擇性 (Optional) 檔案,
其中包含用來回應 ASP.NET 或 HTTP 模組所引發之應用程式層級和工作階段 (Session) 層級事件
的程式碼。
Global.asax 檔案在 ASP.NET 應用程式的根目錄中。
在進行執行階段時,便會剖析 Global.asax,並將其編譯成動態產生的 .NET Framework 類別
(此類別衍生自HttpApplication 基底類別)。
ASP.NET 的設定會自動拒絕任何對於 Global.asax 檔案的直接 URL 要求,因此外部使用者無法
下載或檢視其中的程式碼。


HttpApplication 類別 http://msdn.microsoft.com/zh-tw/library/system.web.httpapplication(VS.80).aspx

定義 ASP.NET 應用程式內所有應用程式物件共用的方法、屬性和事件。
這個類別是使用者在 Global.asax 檔案裡為應用程式定義的基底類別。
HttpApplication 類別的執行個體是建立在 ASP.NET 基礎結構,而不是由使用者直接建立。
HttpApplication 類別的一個執行個體是用來處理存留期內的許多要求,但是一次只能處理一個。
因此,成員變數可以用來儲存每個要求的資料。

在「壓縮網頁大小」中對網頁進行Gzip壓縮,是在「HttpApplication.PreRequestHandlerExecute」事件中
正好發生於 ASP.NET 開始執行事件處理常式 (例如,網頁或 XML Web Service) 之前。」

而要對js、css處理壓縮是要在「HttpApplication.PostReleaseRequestState 事件」

當 ASP.NET 已完成執行所有要求事件處理常式並已儲存要求狀態資料時發生。」


就是要把壓縮的動作給延後到頁面Render之後去處理,js、css檔案是連結外面的檔案,

與aspx頁面本身的事件處理是比較沒有直接關係的。

PS.對於ASP.NET Application生命週期,可以參考MSDN的「ASP.NET 應用程式生命週期概觀


Step1.

延續之前文章的程式,CompressUtils.cs
#region -- CompressCssAndJavascript --
 
/// <summary>
/// Compresses the CSS and javascript.
/// </summary>
/// <param name="app">The app.</param>
public static void CompressCssAndJavascript(HttpApplication app)
{
string contentType = app.Response.ContentType;
 
if (contentType == "text/css" || contentType == "application/x-javascript" || contentType == "text/javascript")
{
app.Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
 
string acceptEncoding = app.Request.Headers["Accept-Encoding"];
 
if (acceptEncoding == null || acceptEncoding.Length == 0) return;
 
acceptEncoding = acceptEncoding.ToLower();
 
if (acceptEncoding.Contains("gzip"))
{
app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
else if (acceptEncoding.Contains("deflate") || acceptEncoding == "*")
{
app.Response.Filter = new DeflateStream(app.Response.Filter, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "deflate");
}
}
}
 
#endregion

針對 ContentType 為 “text/css””text/javascript””application/z-javascript”才進行壓縮處理



Step2.

在Global.asax中增加事件的處理
void Application_PostReleaseRequestState(object sender, EventArgs e)
{
CompressUtils.CompressCssAndJavascript(sender as HttpApplication);
}

來看看執行結果,

image

YSlow的「Compress components with gzip」此項已經沒有任何建議改進的檔案,分數也由之前的F變為A

image

PageSpeed也沒有對壓縮項目提出建議。


壓縮前

image

壓縮後

image


再來看看壓縮後的檔案狀況,可以看出的確是有達到壓縮的目的,

當然CSS檔案原本就很小,所以壓縮的效果比較不明顯(但還是有變小),

而javascript檔案可以明顯看出,由原本的18.2KB縮小到5.2KB,變為原來的1/3不到。

由檔案的Header內容也可以看到,檔案確實有經過gzip處理。

image


當然壓縮的程式碼還可以有改進的空間,例如:

可以不用每次Request進來就做一次壓縮,可以將壓縮過的內容給加入Cache中,減少此類靜態檔案的處理,也減少系統處理的負載。

將原本最小化(minify)的手動工作改由程式進行,減少設計人員的維護工作。



以下是參考的文章:

GZip compress your website's HTML/CSS/Script in code

Building a GZip JavaScript Resource Compression Module for ASP.NET

以上




沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。