ASP.NET MVC 4 RC的JS/CSS打包壓縮功能

打包(Bundling)及壓縮(Minification)指的是將多個js檔或css檔打包成單一檔案並壓縮的做法,如此可減少瀏覽器需下載多個檔案才能完成網頁顯示的延遲感,同時透過移除JS/CSS檔案中空白、註解及修改JavaScript內部函數、變數名稱的壓縮手法,能有效縮小檔案體積,提高傳輸效率,提供使用者更流暢的瀏覽體驗。

在ASP.NET MVC 4 Beta時代便已內建打包壓縮功能,做法是在global.asax.cs的Application_Start加入

BundleTable.Bundles.EnableDefaultBundles();

如此,便可使用以下寫法一口氣將整個Scripts目錄下的JS及Contents目錄下所有CSS打包並壓縮成單一檔案,改善網頁載入效率: (參考)

<script src="@Url.Content("~/Scripts/js")" type="text/javascript"></script>
<script src="@Url.Content("~/Content/CSS")" type="text/javascript"></script>

最近在看ASP.NET MVC 4 RC,發現RC版在打包壓縮做法上又有所革新,變得更加彈性有條理。

原本打包規則被藏在global.asax.cs Application_Start中,RC版起則多了一個新目錄App_Start,其中包含RouteConfig.cs、FilterConfig.cs、BundleConfig.cs三個類別,做法上改為透過WebActivator啟動。新的系統配置將路徑規則、過濾器及打包規則等註冊邏輯由Application_Start中拆出來,各自放在獨立檔案中,管理及修改起來一目瞭然,架構上更漂亮。

BundleConfig.cs的預設內容如下:

using System.Web;
using System.Web.Optimization;
 
namespace MyMvcApplicaiton
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-1.*"));
 
            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                        "~/Scripts/jquery-ui*"));
 
            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));
 
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));
 
            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
 
            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                        "~/Content/themes/base/jquery.ui.core.css",
                        "~/Content/themes/base/jquery.ui.resizable.css",
                        "~/Content/themes/base/jquery.ui.selectable.css",
                        "~/Content/themes/base/jquery.ui.accordion.css",
                        "~/Content/themes/base/jquery.ui.autocomplete.css",
                        "~/Content/themes/base/jquery.ui.button.css",
                        "~/Content/themes/base/jquery.ui.dialog.css",
                        "~/Content/themes/base/jquery.ui.slider.css",
                        "~/Content/themes/base/jquery.ui.tabs.css",
                        "~/Content/themes/base/jquery.ui.datepicker.css",
                        "~/Content/themes/base/jquery.ui.progressbar.css",
                        "~/Content/themes/base/jquery.ui.theme.css"));
        }
    }
}

跟Beta時代很大的差異是將JS與CSS加以群組化,分別定義出jquery, jqueryui, jqueryval, modernizr, css及themes/base/css等群組,讓網頁可以視需要只載入必要的JS及CSS檔案群組,不像先前每次得打包整個目錄,對於JS檔的載入順序及相依性也能做較精準的控調。

而在.cshtml中,則使用Styles.Render及Scripts.Render載入BundleConfig.cs所定義的JS及CSS群組,例如:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/themes/base/css", "~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery", "~/bundles/jqueryui", 
                    "~/bundles/jqueryval")
    @RenderSection("scripts", required: false)
</head>
<body>
    @RenderBody()
</body>
</html>

接著來實測一下,做一個簡單的Index.cshtml,中間只有<div>Hello</div>一行,配合上述的_Layout.cshtml,進行測試,沒想到呈現的原始碼如下,一個個CSS及JS檔都是分開的,沒打包也沒壓縮?

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <link href="/Content/themes/base/jquery.ui.core.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.resizable.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.selectable.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.accordion.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.autocomplete.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.button.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.dialog.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.slider.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.tabs.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.datepicker.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.progressbar.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/jquery.ui.theme.css" rel="stylesheet" type="text/css" />
<link href="/Content/site.css" rel="stylesheet" type="text/css" />
 
    <script src="/Scripts/modernizr-2.0.6-development-only.js" type="text/javascript"></script>
 
    <script src="/Scripts/jquery-1.6.2.js" type="text/javascript"></script>
<script src="/Scripts/jquery-ui-1.8.11.js" type="text/javascript"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
 
    
</head>
<body>
    <div>Hello</div>
</body>
</html>

原來,這也是ScriptBundle及StyleBundle的貼心之處,在偵錯模式下,會展現CSS及JS原貌,方便開發人員檢視原始碼找問題與除錯。要見識它的打包壓縮效果,記得要設定<compilation debug="false" targetFramework="4.0" />。

關閉偵錯模式後,網頁的原始碼就變成以下的樣子,一個群組只有一個<link>或<script>,而href及src會指向/Content/css?v=ji3nXsakWko…(包含雜湊碼參數,以確保檔案變動時只會載入新版)格式的連結,傳回多個檔案打包及壓縮後的內容:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <link href="/Content/themes/base/css?v=UM62...略" rel="stylesheet" type="text/css" />
<link href="/Content/css?v=ji3n...略" rel="stylesheet" type="text/css" />
 
    <script src="/bundles/modernizr?v=XGaE...略" type="text/javascript"></script>
 
    <script src="/bundles/jquery?v=3AwA...略" type="text/javascript"></script>
<script src="/bundles/jqueryui?v=bMdf...略" type="text/javascript"></script>
<script src="/bundles/jqueryval?v=uFE7...略" type="text/javascript"></script>
 
    
</head>
<body>
    <div>Hello</div>
</body>
</html>

最後,實際測量二者的效能差別:


在未打包壓縮前,載入網頁需要發出20個請求,總共傳輸5,992+812,541=818,533 Bytes的資料。


打包壓縮後,請求數下降到7個,資料傳輸量也減少為2,274+352,454=354,728 Bytes,資料傳輸量只有原本的43.33%!

在開發ASP.NET MVC 4專案時,不要忘記這個有用的機制。

歡迎推文分享:
Published 05 June 2012 09:24 PM 由 Jeffrey
Filed under:
Views: 34,307



意見

# KenChao said on 07 June, 2012 03:16 AM

請問非MVC 4.0的話,是否有其他方法可以做到類似的效果呢,非常好奇.

# Jeffrey said on 07 June, 2012 03:45 AM

to KenChao, 這部分未來會內建在ASP.NET 4.5中,不管WebForm或MVC都可以使用。(參考: www.asp.net/.../whats-new)

# KKBruce said on 23 July, 2012 04:54 AM

nuget.org/.../microsoft.web.optimization

好像規劃是放到 nuget.org。

# Ken said on 10 January, 2013 01:31 AM

雞婆一下,除了關掉Debug之外,打包壓縮也可以透過下方式達成(不需關閉debug):

BundleTable.EnableOptimizations = true;

詳情可參考: www.asp.net/.../bundling-and-minification

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<June 2012>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication