Asp.Net MVC 捆綁(Bundle)
大多數瀏覽器會對同一域名的請求限制請求數量,一般是在8個以內。每次最多可以同時請求8個,要是資源多於8個,那麼剩下的就要排隊等待請求了。所以為了提高首次載入頁面的速度。提高請求併發請求數量,降低請求次數就是一個很重要的點。
Bundle
Asp.Net MVC4和.NET Framework4.5提供了支援捆綁和壓縮的新類庫System.Web.Optimization
。
該類庫提供瞭如下特性:
- 捆綁-將多個資原始檔(javascript,css)合併成一個單獨的檔案,但是合併成的單獨檔案必須是相同型別,要麼都是JavaScript要麼都是CSS。
- 壓縮資原始檔-清理空格,換行等,壓縮檔案大小。
- 自動清理快取-服務端更新資源時,客戶端不再使用快取資源,而是重新從服務端快取。
1. 定義Bundle
在App_Start
檔案中新增一個BundleConfig.cs
檔案。實現靜態RegisterBundles
方法。該方法用來建立,註冊和配置bundle。(在該目錄下程式碼最好把他們的名稱空間去掉 ".App_Start",保持一個統一的高等級的名稱空間)。
呼叫
BundleCollection.Add()
方法新增捆綁資源,該方法引數為ScriptBundle
或StyleBundle
。ScriptBundle
和StyleBundle
需要傳遞一個虛擬路徑給建構函式。該虛擬路徑其實就是該捆綁的名稱或者識別符號。所以該虛擬路徑可以任意設定,並不需要匹配物理路徑。Bundle
的Include
方法包含一個或者多個指令碼。通過引用該虛擬路徑就可以使用這些捆綁的資源
@Script.Render("~/bundles/jquery")
。Debug模式下預設沒有開啟捆綁和壓縮,釋出模式下預設是開啟的。
public static void RegisterBundles(BundleCollection bundles)
{
//該值為true,在任何模式下都使用捆綁和壓縮。
//BundleTable.EnableOptimizations = true;
//新增名稱為“~/bundles/jquery”指令碼捆綁
bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));
//新增名稱為“~/Content/css”樣式捆綁
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/Site.css"));
}
使用{version}
佔位符可以在使用NuGet更新Jquery版本時,不需要更新Bundle的引用,自動使用最新的Jquery版本。
ScriptBundle
和StyleBundle
的Include
方法引數是一個字串型別的陣列,所以一個Bundle例項可以新增多個檔案。
如
bundles.Add(new StyleBundle("~/Content/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"));
但是Bundle類也提供了IncludeDirectory
方法,可以新增指定目錄下的指定檔案。
//新增Content/themes/base目錄下的所有css檔案
bundles.Add(new StyleBundle("~/Content/css"").IncludeDirectory("~/Content/themes/base", "*.css"));
使用萬用字元要注意:
- 使用萬用字元新增資源時。這些資原始檔是按照名稱來排序的。
2. 啟用Bundle
在Global.asax的Appliaction_Start方法中呼叫之前的定義的方法,BundleConfig.RegisterBundles(BundleTable.Bundles)
啟用Bundle。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
3. 使用Bundle
如果我們需要在頁面中使用這些資源時。可以通過Styles和Scripts來引入。如果要使用捆綁的Style,可以在頁面中新增@Styles.Render("~/Content/css")
。如果要使用捆綁的Script,可以在頁面中新增@Script.Render("~/bundles/jquery")
。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 我的 ASP.NET 應用程式</title>
//引入樣式捆綁
@Styles.Render("~/Content/css")
</head>
<body>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 應用程式</p>
</footer>
</div>
//引入js捆綁
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
可以把CSS樣式檔案置頂,JavaScript檔案置底,來優化網頁。但是modernizr.js
檔案要放在頁面頂部,因為有些樣式檔案需要。
使用CDN
Bundle對CDN也提供了很好的支援。
public static void RegisterBundles(BundleCollection bundles)
{
//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js"));
bundles.UseCdn = true; //啟用cdn
//新增地址
var jqueryCdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery",jqueryCdnPath).Include("~/Scripts/jquery-{version}.js"));
}
在使用CDN時,要應對沒有獲取到資源的情況。
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript">
if (typeof jQuery == 'undefined') {
var e = document.createElement('script');
e.src = '@Url.Content("~/Scripts/jquery-1.7.1.js")';
e.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(e);
}
</script>
Bundle快取
瀏覽器是根據URL來快取資料的。瀏覽器無論何時請求資源,都會根據URL來檢查快取裡是否包含了該資原始檔。如果包含了,瀏覽器就不會再去請求,而是使用快取的檔案,來渲染。
Bundle機制使我們每次修改資原始檔時都會在URL後自動新增一個雜湊值,從而避免瀏覽器快取,不能及時更新資源的情況。
v=******,後面的值就是雜湊值。Bundle
在Debug模式下預設是沒有開啟的。在釋出模式下才會開啟。但是我們可以在BundleConfig下新增BundleTable.EnableOptimizations = true;
開啟捆綁模式。
Bundle注意事項
一個
Bundle
一般包含多個檔案,如果我們只是修改了其中的一個檔案,那麼Bundle
的雜湊值也會改變,就會更新Bundle
的所有檔案。捆綁和縮小主要降低了第一次訪問頁面時載入的時間。此時靜態資源就會被快取起來(js,css,圖片)。當訪問其他頁面,且該頁面的資源地址和第一次訪問的地址相同時,就會從快取裡獲取,不再向服務端獲取。
如果資源過多,使用CDN,比使用
Bundle
更有效。當然Bundle
也可以結合CDN使用。 通過使用CDN,可以減輕每個主機名8個併發連線的瀏覽器限制。因為CDN的主機名與您的主機站點不同,CDN上的資產請求不會與您的主機環境的8個併發連線數計數。Bundle
最好按照功能來區分捆綁。例如,預設的ASP.Net應用程式的NET MVC模板建立了一個與jQuery分離的jQuery驗證包。因為所建立的預設檢視輸入輸出值,所以它們需要驗證包。
如有不對,請多多指教。
參考:
- Bundleing and Minification
- Asp.Net MVC 4 Web 程式設計