آموزش مقدماتی Bundling و Minification در ASP.NET MVC + معرفی دوره
«بستهبندی» (Bundling) و «کمینهسازی» (Minification)، دو روش بسیار محبوب برای افزایش کارایی وب اپلیکیشنهای امروزی بهشمار میروند. عمل Bundling تعداد «درخواستهای» (Requests) ارسالی به سمت سرور، و Minification، اندازه assetهای درخواستی (فایلهای ایستا روی سرور) را کاهش میدهد. در این مطلب، Bundling و Minification در ASP.NET MVC و نحوه کار آن بیان شده است. پس از آن، تاثیر اِعمال این دو ویژگی روی سرعت بارگذاری صفحات وب را بررسی خواهیم کرد. همچنین در مورد دیباگ کردن اسکریپتهای جاوا اسکریپت و نحوه تنظیمات آن نیز توضیحاتی ارائه شده است.
امروزه، وب اپلیکیشنها به لطف وجود دو مولفه فوقالعاده، یعنی جاوا اسکریپت و CSS، «پاسخگوتر» (Responsive) و جذابتر هستند و میتوان گفت که پلتفرم وب به وسیله این دو مولفه، قدرتی مهارنشدنی پیدا کرده است. در عین حال ممکن است، افزایش تعداد و حجم این فایلهای CSS و جاوا اسکریپت، اثرات منفی روی سرعت بارگذاری صفحات داشته باشند. در نوشتار پیشِ رو، سعی شده است نحوه استفاده و کد نویسی Bundling و Minification در ASP.NET MVC تا حد قابل قبولی پوشش داده شود.
Bundling و Minification در ASP.NET MVC
همانطور که گفته شد، باندلینگ و مینیفیکیشن، دو تکنیکی هستند که شما میتوانید برای بهبود زمان بارگذاری درخواست، در اِیاِسپی داتنت ۴٫۵ استفاده کنید. Bundling زمان بارگذاری را از طریق کاهش تعداد درخواستهای ارسالی از کاربر به سمت سرور، بهبود میدهد. به وسیله Minification نیز اندازه assetهایی کاهش پیدا میکنند که در درخواست وجود دارند. در نتیجه، سرعت بارگذاری صفحات بهبود مییابد. منظور از assetها، همان فایلهای ایستای روی سرور، مانند تصاویر، فایلهای CSS، جاوا اسکریپت و غیره هستند که میخواهیم آنها را در دسترس دنیای بیرونی (مخاطبین برنامه وب) قرار دهیم.
امروزه، اکثر مرورگرهای رایج، تعداد «اتصالات همزمان» (Simultaneous Connections) برای هر «نام میزبان» (Hostname) را به ۶ اتصال محدود میکنند. اینجا Hostname برچسبی است که به یک دستگاه متصل به اینترنت، برای شناسایی آن در اَشکال مختلف ارتباطات استفاده میشود. یعنی در صورتی که ۶ درخواست در حال پردازش باشند، درخواستهای اضافی برای assetها بهوسیله مرورگر در صف قرار میگیرند. تصویر زیر، زبانه Network از «ابزارهای توسعهدهنده» (Developer Tools) مرورگر IE را نشان میدهد. برای دسترسی به این ابزار میتوانیم از کلید میانبر F12 استفاده کنیم. زمانبندی asset-های مورد نیاز در نمای «About»، در این تصویر قابل مشاهده است.
نوارهای خاکستری رنگ، زمان قرارگیری درخواست در صف انتظار (با توجه به محدودیت اتصال ۶ تایی) بهوسیله مرورگر را نشان میدهند. نوار زرد رنگ، بیانگر «زمان اولین بایتِ» (Time to First Byte) درخواست است، یعنی مدت زمانی که از ارسال درخواست تا دریافت اولین پاسخ از سرور طول کشیده است.
نوارهای آبی رنگی که مشاهده میکنید نیز، زمان صرف شده برای دریافت دادههای پاسخ از سرور هستند. برای دریافت اطلاعات دقیق زمانبندیِ asset مورد نظر، میتوانید روی آن دابِلکلیک کنید. به عنوان مثال، تصویر زیر جزئیات زمان بارگذاری فایل /Scripts/MyScripts/JavaScript6.js را نشان میدهد.
تصویر بالا در مورد رویداد Start است که زمان قرار گرفتنِ درخواست را در صف بیان میکند. زیرا مرورگر، تعداد اتصالات همزمان را محدود کرده است. در این مورد خاص، درخواست به مدت ۴۶ میلیثانیه در صف منتظر ماند تا درخواست قبلی تکمیل شود.
بسته بندی یا Bundling در ASP.NET چیست ؟
Bundling یکی از ویژگیهای جدید ASP.NET 4.5 به شمار میرود که امکان ترکیب یا «باندل کردن» (گنجاندن) چندین فایل را در یک فایل فراهم میکند. شما میتوانید باندلهای مختلفی همچون باندل CSS، باندل جاوا اسکریپت و غیره را ایجاد کنید. فایلهای کمتر به معنای درخواستهای HTTP کمتری است و این باعث میشود تا عملکرد بارگذاری صفحه اول بهبود پیدا کند.
تصویر زیر، همان زمانبندی نمای About را نشان میدهد که قبلاً دیدیم، با این تفاوت که اینبار، ویژگی باندلینگ و کمینهسازی روی آن اعمال شده است.
کمینه سازی Minification در ASP.NET چیست ؟
با استفاده از Minification، انواع بهینهسازی مختلف کدها، روی اسکریپتها یا دستورات CSS اعمال میشود. این عملیات، «فضای خالی» (White Space) غیر ضروری و «توضیحات» (Comments) را حذف میکند، همچنین نام متغیرها را نیز با هدف کوتاهسازی، به یک کاراکتر کاهش میدهد.
تابع جاوا اسکریپتی زیر را در نظر بگیرید.
1AddAltToImg = function (imageTagAndImageID, imageContext) {
2 ///<signature>
3 ///<summary> Adds an alt tab to the image
4 // </summary>
5 //<param name="imgElement" type="String">The image selector.</param>
6 //<param name="ContextForImage" type="String">The image context.</param>
7 ///</signature>
8 var imageElement = $(imageTagAndImageID, imageContext);
9 imageElement.attr('alt', imageElement.attr('id').replace(/ID/, ''));
10}
پس از انجام کمینهسازی، اسکریپت minify شدهای بهصورت زیر خواهیم داشت:
1AddAltToImg = function (n, t) { var i = $(n, t); i.attr("alt", i.attr("id").replace(/ID/, "")) }
همانطور که مشاهده میکنید، علاوه بر حذف کامنتها و فضاهای خالی غیر ضروری، نام پارامترها و متغیرها نیز به صورت زیر تغییر پیدا میکند (کوتاه میشود):
نام اصلی قبل از کمینهسازی | نام تغییر یافته پس از کمینهسازی |
imageTagAndImageID | n |
imageContext | t |
imageElement | i |
تاثیر Bundling و Minification روی عملکرد برنامه
جدول زیر چندین تفاوت زمانی مهم، بین حالتی که تمام assetها به صورت جداگانه فهرست میشوند و همینطور حالتی که Bundling و Minification (به اختصار B/M) اِعمال شدهاند را در یک نمونه برنامه نشان میدهد.
با استفاده از B/M | بدون استفاده از B/M | میزان تغییر | |
درخواستهای فایل | ۹ | ۳۴ | ٪۲۵۶ |
KB ارسالی | ۳٫۲۶ | ۱۱٫۹۲ | ٪۲۶۶ |
KB دریافتی | ۳۸۸٫۵۱ | ۵۳۰ | ٪۳۶ |
زمان بارگذاری | ۵۱۰ میلیثانیه | ۷۸۰ میلیثانیه | ٪۵۳ |
همانطور که مشاهده میشود، میزان بایتهای ارسالی همراه با ویژگی باندلینگ، کاهش قابل توجهی داشته است، زیرا مرورگرها با بکارگیری سرآیندهایِ HTTP روی درخواستها، آنها را طولانیتر میکنند. اما به دلیل اینکه فایلهای بزرگ ما (فایلهای Scripts\jquery-ui-1.8.11.min.jsو jquery-1.7.1.min.js موجود در پوشه Scripts)، از قبل «کمینه» (Minified) شدهاند، کاهش بایتهای دریافتی آنقدر زیاد نیست.
توجه داشته باشید که، زمانبندیهای مربوط به نمونه برنامه بالا، با استفاده از ابزار «Fiddler»، شبکهای کمسرعت را شبیهسازی کرده است. (برای تغییر آن میتوانید در Fiddler از منوی Rules، ابتدا Performance و در مرحله بعد، Simulate Modem Speeds را انتخاب کنید.)
دیباگ جاوا اسکریپت Bundling و Minification شده
دیباگ کردن جاوا اسکریپت در محیط توسعه، یعنی زمانی که «مولفه کامپایل» (Compilation Element) در Web.config به صورتdebug="true" تنظیم شده است، کار سختی نیست. زیرا فایلهای جاوا اسکریپت هنوز Bundling یا Minification نشدهاند. شما همچنین میتوانید نسخه «انتشار» (Release) از فایلهای جاوا اسکریپت، (که باندلینگ و کمینهسازی شدهاند) را نیز دیباگ کنید.
با استفاده از ابزارهای توسعهدهنده مرورگر IE، میتوانیم تابع جاوا اسکریپتی کمینه و باندلینگ شده را با مراحلی که در ادامه بیان میشود، دیباگ کنیم:
- زبانه Script و پس از آن دکمه Start debugging را انتخاب کنید.
- باندلِ حاوی تابع جاوا اسکریپتی که میخواهید دیباگ کنید را به وسیله دکمه Assets انتخاب کنید.
- جاوا اسکریپت کمینه شده را با انتخاب دکمه Configuration و پس از آن Format JavaScript، قالببندی کنید.
- در باکس ورودی Search Script، نام تابعی که قصد دیباگ آن را دارید، بنویسید. (در تصویر زیر،AddAltToImg در باکس ورودی Search Script وارد شده است.)
تنظیم و کنترل Bundling و Minification در ASP.NET MVC
Bundling و Minification در ASP.NET MVC را می توانیم با تنظیم مقدار ویژگی debug در مولفه کامپایل، که در فایل Web.configوجود دارد، فعال یا غیرفعال کنیم. در XML زیر، مشخصه debugروی «true» تنظیم شده است، و معنی آن این است که قابلیت Bundling و Minification غیرفعال است.
1<system.web>
2 <compilation debug="true" />
3 <!-- Lines removed for clarity. -->
4</system.web>
برای فعالکردن Bundling و Minification در ASP.NET MVC، مقدار debugرا روی «false» تنظیم میکنیم.
شما همچنین میتوانید تنظیمات Web.config را با ویژگی EnableOptimizations در کلاس BundleTable لغو کنید. کدهای زیر Bundling و Minification را فعال و همه تنظیمات موجود در فایل Web.config را لغو میکنند.
1public static void RegisterBundles(BundleCollection bundles)
2{
3 bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
4 "~/Scripts/jquery-{version}.js"));
5
6 // Code removed for clarity.
7 BundleTable.EnableOptimizations = true;
8}
تا پیش از اینکه ویژگیEnableOptimizations، true نشود یا ویژگی debug در فایل Web.config روی false تنظیم نشده باشد، فایلهای ما باندل و کمینه نمیشوند. علاوه بر این، بهجای نسخه «min.» فایلها، نسخههای کامل، انتخاب خواهند شد. توجه داشته باشید کهEnableOptimizationsویژگی debug را در مولفه کامپایل در فایل Web.config لغو میکند.
استفاده از Bundling و Minification در وب فرمها و صفحات وب
در این قسمت، نحوه باندلینگ و مینیفیکیشن در وب پیجها و وب فُرمها شرح داده میشود.
Bundling و Minification در صفحات وب
افزودن Bundling و Minification به وبسایتها از همان روش مورد استفاده توسط ASP.NET MVC و Web Form-ها پیروی میکند:
- اعلان و ثبت Bundle-ها
- بکارگیری Bundle-ها از درون «نماها» (Views)
برای شروع، یک «Web Pages site» جدید میسازیم. سپس فایل_AppStart.cshtml را باز میکنیم.
کدهای زیر را جایگزین محتویات آن میکنیم.
1@using System.Web.Optimization;
2
3@{
4 var bundles = BundleTable.Bundles;
5
6 bundles.UseCdn = true; //enable CDN support
7
8 //add link to jquery on the CDN
9 var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
10
11 bundles.Add(new ScriptBundle("~/bundles/jquery",
12 jqueryCdnPath).Include(
13 "~/Scripts/jquery-{version}.js"));
14
15 bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
16 "~/Scripts/jquery-ui-{version}.js"));
17
18 bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
19 "~/Scripts/jquery.unobtrusive*",
20 "~/Scripts/jquery.validate*"));
21
22 bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
23 "~/Scripts/modernizr-*"));
24
25 bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
26
27 bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
28 "~/Content/themes/base/jquery.ui.core.css",
29 "~/Content/themes/base/jquery.ui.resizable.css",
30 "~/Content/themes/base/jquery.ui.selectable.css",
31 "~/Content/themes/base/jquery.ui.accordion.css",
32 "~/Content/themes/base/jquery.ui.autocomplete.css",
33 "~/Content/themes/base/jquery.ui.button.css",
34 "~/Content/themes/base/jquery.ui.dialog.css",
35 "~/Content/themes/base/jquery.ui.slider.css",
36 "~/Content/themes/base/jquery.ui.tabs.css",
37 "~/Content/themes/base/jquery.ui.datepicker.css",
38 "~/Content/themes/base/jquery.ui.progressbar.css",
39 "~/Content/themes/base/jquery.ui.theme.css"));
40
41}
بکارگیری Bundleها
فایل layout را باز و تگهای پیوند CSS و اسکریپت موجود در تگ <head> را با رفرنسهای مربوط به Bundle جایگزین میکنیم. کدهای اولیه در ادامه نشان داده شده است.
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <title>@Page.Title - My ASP.NET Web Page</title>
6 <link href="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
7 <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
8 <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
9 <script src="~/Scripts/jquery-1.7.1.min.js"></script>
10 <script src="~/Scripts/jquery-ui-1.8.20.js"></script>
11 <script src="~/Scripts/modernizr-2.5.3.js"></script>
12 <meta name="viewport" content="width=device-width" />
13 </head>
پس از از اعمال تغییرات، کدهایی به شکل زیر خواهیم داشت.
1@using System.Web.Optimization;
2<!DOCTYPE html>
3<html lang="en">
4 <head>
5 <meta charset="utf-8" />
6 <title>@Page.Title - My ASP.NET Web Page</title>
7
8 @Styles.Render("~/Content/themes/base/css", "~/Content/css");
9
10 <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
11
12 @Scripts.Render("~/bundles/jquery",
13 "~/bundles/jqueryui",
14 "~/bundles/modernizr");
15
16 <meta name="viewport" content="width=device-width" />
17 </head>
با تغییرات صورت گرفته، CSS و جاوا اسکریپت به صورت Bundle تحویل داده میشوند. باندلها را میتوان در «نماها» (Views) با استفاده از متد Render ارجاع داد (Styles.Render
برای CSS و Scripts.Render
برای جاوا اسکریپت).
پیکربندی پیشفرض برای صفحات وب، مولفه کامپایل را روی debug=true تنظیم میکند. تا وقتی که پیکربندی کامپایل به این صورت باشد، هیچکدام از اَعمال باندلینگ یا کمینهسازی انجام نمیشوند. فایل Web.config را باز و ویژگی debugدر عناصر کامپایل را مطابق شکل زیر به false تغییر میدهیم:
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <system.web>
4 <compilation debug="false" targetFramework="4.0" />
5 </system.web>
6 <!--Elements removed for clarity.-->
7</configuration>
Bundling و Minification در وب فرم ها
برای این منظور، یک برنامه جدید ASP.NET Web Forms با چارچوب دات نت ۴٫۵ ایجاد میکنیم.
برنامه و پس از آن، ابزارهای توسعهدهنده IE یعنی Developer Tools را اجرا میکنیم. برای مشاهده فایلهای جاوا اسکریپت، میتوان زبانه Script را انتخاب و از دکمه Assets استفاده کرد.
با انتخاب یکی از فایلهای جاوا اسکریپت، محتویات آن در پنجره نمایش داده میشود. توجه داشته باشید که در اینجا از فایلهای کامل (نسخه کمینه نشده) استفاده شده است.
ایجاد باندل های جی کوئری
jQuery، jQuery.UI و jQuery validation را به کلاس BundleConfig در پوشه App_Start اضافه کنید. کد کلاس به صورت زیر است.
1using System.Web.Optimization;
2
3public class BundleConfig
4{
5 public static void RegisterBundles(BundleCollection bundles)
6 {
7 bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
8 "~/Scripts/jquery-{version}.js"));
9
10 bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
11 "~/Scripts/jquery-ui-{version}.js"));
12
13 bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
14 "~/Scripts/jquery.unobtrusive*",
15 "~/Scripts/jquery.validate*"));
16
17 bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include(
18 "~/Scripts/WebForms/WebForms.js",
19 "~/Scripts/WebForms/WebUIValidation.js",
20 "~/Scripts/WebForms/MenuStandards.js",
21 "~/Scripts/WebForms/Focus.js",
22 "~/Scripts/WebForms/GridView.js",
23 "~/Scripts/WebForms/DetailsView.js",
24 "~/Scripts/WebForms/TreeView.js",
25 "~/Scripts/WebForms/WebParts.js"));
26
27 bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include(
28 "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js",
29 "~/Scripts/WebForms/MsAjax/MicrosoftAjaxApplicationServices.js",
30 "~/Scripts/WebForms/MsAjax/MicrosoftAjaxTimer.js",
31 "~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js"));
32
33 bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
34 "~/Scripts/modernizr-*"));
35 }
36}
ثبت باندل ها
«قالبها» (Templates) کدی به صورت زیر در متد Application_Start (در فایل Global.asax) میسازند.
1void Application_Start(object sender, EventArgs e)
2{
3 BundleConfig.RegisterBundles(BundleTable.Bundles);
4 AuthConfig.RegisterOpenAuth();
5}
ارجاع به باندل ها
همانطور که در کدهای زیر مشاهده میکنید، باندلهای جی کوئری را باید به نشانهگذاری <asp:PlaceHolder> اضافه کنیم.
1<asp:PlaceHolder runat="server">
2 <%: Scripts.Render("~/bundles/modernizr") %>
3 <%: Scripts.Render("~/bundles/jquery") %>
4 <%: Scripts.Render("~/bundles/jqueryui") %>
5 </asp:PlaceHolder>
پس از آن، ارجاعیات اسکریپت jQuery را در تگ ScriptManager، همانگونه که در زیر نشان داده شده است، از حالت «توضیح» (Comment) خارج میکنیم.
1<body>
2 <form runat="server">
3 <asp:ScriptManager runat="server">
4 <Scripts>
5 <%--
6 <asp:ScriptReference Name="jquery" />
7 <asp:ScriptReference Name="jquery.ui.combined" />
8 --%>
9 </Scripts>
10 </asp:ScriptManager>
11 <header>
باندل های CSS
فایل Bundle.config ، که حاوی نشانهگذاریهایی برای ایجاد باندلهای سَبکهای CSS است، را بررسی کنید.
1<?xml version="1.0" encoding="utf-8" ?>
2<bundles version="1.0">
3 <styleBundle path="~/Content/css">
4 <include path="~/Content/Site.css" />
5 </styleBundle>
6 <styleBundle path="~/Content/themes/base/css">
7 <include path="~/Content/themes/base/jquery.ui.core.css" />
8 <include path="~/Content/themes/base/jquery.ui.resizable.css" />
9 <include path="~/Content/themes/base/jquery.ui.selectable.css" />
10 <include path="~/Content/themes/base/jquery.ui.accordion.css" />
11 <include path="~/Content/themes/base/jquery.ui.autocomplete.css" />
12 <include path="~/Content/themes/base/jquery.ui.button.css" />
13 <include path="~/Content/themes/base/jquery.ui.dialog.css" />
14 <include path="~/Content/themes/base/jquery.ui.slider.css" />
15 <include path="~/Content/themes/base/jquery.ui.tabs.css" />
16 <include path="~/Content/themes/base/jquery.ui.datepicker.css" />
17 <include path="~/Content/themes/base/jquery.ui.progressbar.css" />
18 <include path="~/Content/themes/base/jquery.ui.theme.css" />
19 </styleBundle>
20</bundles>
همچنین میتوانید باندلهای سَبک خود را به فایل Bundle.configاضافه کنید. نشانهگذاریهای زیر، ارجاعات مربوط به باندلهای CSS و هچنین باندلهای جاوا اسکریپت را نشان میدهند. توجه داشته باشید که میتوانید چندین باندل را در یک فراخوانی، با استفاده از متد Render انجام دهید.
1<%: Styles.Render("~/Content/themes/base/css",
2 "~/Content/css") %>
3<%: Scripts.Render("~/bundles/modernizr") %>
4<%: Scripts.Render("~/bundles/jquery",
5 "~/bundles/jqueryui") %>
استفاده از Bundling و Minification در ASP.NET MVC
در این بخش، یک پروژه ASP.NET MVC، برای بررسی و امتحان باندلینگ و کمینهسازی میسازیم. پس قبل از هر چیز، یک پروژه جدید اینترنتی ASP.NET MVC با نامMvcBM و بدون تغییر هیچ یک از پیشفرضها ایجاد میکنیم.
فایل App\_Start\BundleConfig.cs را باز و متد RegisterBundlesرا بررسی میکنیم. این متد برای ایجاد، «ثبت» (Register) و پیکربندی باندلها استفاده میشود. کدهای زیر بخشی از متد RegisterBundles را نشان میدهند.
1public static void RegisterBundles(BundleCollection bundles)
2{
3 bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
4 "~/Scripts/jquery-{version}.js"));
5 // Code removed for clarity.
6}
یکی از اصطلاحات حوزه نرمافزار، «کاراکتر جانشین» (Wildcard) است که معمولا با یک کاراکتر تکی نشان داده میشود. مانند کاراکتر «ستاره» (*) که میتواند به عنوان جایگزینی برای تعدادی کاراکتر یا رشتهای خالی تفسیر شود. این مفهوم اغلب در جستجوی فایل استفاده میشود، که در این صورت، نیازی به نوشتن نام کامل آن نیست. مثلاً عبارت «a*e» میتواند شامل هر رشتهای باشد که با کاراکتر «a» آغاز و با «e» پایان یافته است (مانند apple).
کدهای بالا یک باندل جاوا اسکریپتی جدید به نام ~/bundles/jquery میسازند که تمام فایلهای مناسب (منظور، فایلهای مناسبی نظیر اشکالزدایی یا کمینهسازی است و نه فایلهای vsdoc.) در پوشه Scripts و منطبق با کاراکتر جایگزین ~/Scripts/jquery-{version}.jsرا شامل میشود. برای ASP.NET MVC، با پیکربندی دیباگ، فایل jquery-1.7.1.js و در پیکربندی انتشار (Release)، jquery-1.7.1.min.js به باندل اضافه خواهد شد.
فریم ورک Bundling از چندین قاعده اصلی پیروی میکند، که در ادامه شرح داده شدهاند.
- انتخاب فایل .min برای انتشار، زمانی که FileX.min.jsو FileX.jsوجود دارد.
- نسخه غیر .min برای دیباگ کردن انتخاب میشود.
- نادیده گرفتن فایلهای -vsdoc (مانندjquery-1.7.1-vsdoc.js)، که فقط توسط محیط IntelliSense استفاده میشوند.
«انطباقِ» (Matching) کاراکترِ جانشینِ{version} که در بالا دیدیم، برای ایجاد خودکار یک باندل جی کوئری، با نسخه مناسب jQuery موجود در پوشه Scriptsشما استفاده میشود. در این مثال، استفاده از کاراکتر جانشین مزایای زیر را به همراه دارد:
- به شما امکان میدهد تا از NuGet برای بهروزرسانی کتابخانه jQuery به نسخه جدیدتر آن استفاده کنید. بدون اینکه نیاز به تغییر کدهای باندلینگ قبلی یا ارجاعیات jQuery در صفحات خود داشته باشید.
- به طور خودکار، نسخه کامل را برای پیکربندی دیباگ، و نسخه .min را برای نسخههای انتشار انتخاب میکند.
استفاده از CDN
کدهای زیر باندل jQuery محلی را با یک باندل شبکه توزیع محتوای (CDN) جی کوئری، جایگزین میکند.
1public static void RegisterBundles(BundleCollection bundles)
2{
3 //bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
4 // "~/Scripts/jquery-{version}.js"));
5
6 bundles.UseCdn = true; //enable CDN support
7
8 //add link to jquery on the CDN
9 var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
10
11 bundles.Add(new ScriptBundle("~/bundles/jquery",
12 jqueryCdnPath).Include(
13 "~/Scripts/jquery-{version}.js"));
14
15 // Code removed for clarity.
16}
در کد بالا و در حالت انتشار، jQuery از CDN درخواست میشود و در حالت دیباگ، نسخه دیباگ jQuery به صورت محلی واکشی میشود. هنگام استفاده از CDN، باید یک ساز و کار «بازگشت» (Fallback) داشته باشیم، برای مواقعی که درخواست CDN با شکست مواجه میشود.
تکه «نشانهگذاری» (Markup) زیر (از انتهای فایل Layout)، اسکریپت اضافه شده به درخواست jQuery، در مواقع خرابی CDN را نشان میدهد.
1</footer>
2
3 @Scripts.Render("~/bundles/jquery")
4
5 <script type="text/javascript">
6 if (typeof jQuery == 'undefined') {
7 var e = document.createElement('script');
8 e.src = '@Url.Content("~/Scripts/jquery-1.7.1.js")';
9 e.type = 'text/javascript';
10 document.getElementsByTagName("head")[0].appendChild(e);
11
12 }
13 </script>
14
15 @RenderSection("scripts", required: false)
16 </body>
17</html>
نحوه ایجاد باندل در ASP.NET MVC
متد Include از کلاس Bundle، آرایهای از رشتهها را دریافت میکند. به این ترتیب که هر رشته نشاندهنده مسیری مجازی به منبع است.
کد زیر از متد RegisterBundlesدر فایل App\_Start\BundleConfig.cs، چگونگی اضافه شدن چندین فایل به یک باندل را نشان میدهد:
1bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
2 "~/Content/themes/base/jquery.ui.core.css",
3 "~/Content/themes/base/jquery.ui.resizable.css",
4 "~/Content/themes/base/jquery.ui.selectable.css",
5 "~/Content/themes/base/jquery.ui.accordion.css",
6 "~/Content/themes/base/jquery.ui.autocomplete.css",
7 "~/Content/themes/base/jquery.ui.button.css",
8 "~/Content/themes/base/jquery.ui.dialog.css",
9 "~/Content/themes/base/jquery.ui.slider.css",
10 "~/Content/themes/base/jquery.ui.tabs.css",
11 "~/Content/themes/base/jquery.ui.datepicker.css",
12 "~/Content/themes/base/jquery.ui.progressbar.css",
13 "~/Content/themes/base/jquery.ui.theme.css"));
متد IncludeDirectoryاز کلاس Bundle، برای افزودن همه فایلهای موجود در یک فهرست (و در صورت تمایل همه زیر شاخهها) استفاده میشود. منظور، همان فایلهایی است که با الگوی جستجو مطابقت دارند. این متد در کدهای زیر استفاده شده است.
1public Bundle IncludeDirectory(
2 string directoryVirtualPath, // The Virtual Path for the directory.
3 string searchPattern) // The search pattern.
4
5public Bundle IncludeDirectory(
6 string directoryVirtualPath, // The Virtual Path for the directory.
7 string searchPattern, // The search pattern.
8 bool searchSubdirectories) // true to search subdirectories.
باندلها با استفاده از متد Render در Viewها ارجاع داده میشوند. نشانهگذاری زیر از فایل Views\Shared\_Layout.cshtml، نشاندهنده این است که viewهای پیشفرض پروژه اینترنتی ASP.NET، چگونه به باندلهای CSS و جاوا اسکریپت اشاره میکنند.
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 @* Markup removed for clarity.*@
5 @Styles.Render("~/Content/themes/base/css", "~/Content/css")
6 @Scripts.Render("~/bundles/modernizr")
7</head>
8<body>
9 @* Markup removed for clarity.*@
10
11 @Scripts.Render("~/bundles/jquery")
12 @RenderSection("scripts", required: false)
13</body>
14</html>
توجه داشته باشید که متدهای Render، آرایهای از رشتهها را میگیرند، بنابراین میتوانید چندین باندل را با تنها یک خط کد اضافه کنید. ما معمولاً از متدهای Render استفاده میکنیم. یعنی متدهایی که HTML لازم را برای ارجاع به assetها ایجاد میکنند.
همچنین میتوان از متد URL هم برای ایجاد URL به asset، بدون نشانهگذاری مورد نیاز برای ارجاع به assetها استفاده کرد. فرض کنید میخواهیم از ویژگی جدید HTML5 یعنی async استفاده کنیم. کدهای زیر، نحوه ارجاع به modernizr (نام کتابخانهای جاوا اسکریپتی) را با استفاده از روش URL نشان میدهند.
1<head>
2 @*Markup removed for clarity*@
3 <meta charset="utf-8" />
4 <title>@ViewBag.Title - MVC 4 B/M</title>
5 <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
6 <meta name="viewport" content="width=device-width" />
7 @Styles.Render("~/Content/css")
8
9 @* @Scripts.Render("~/bundles/modernizr")*@
10
11 <script src='@Scripts.Url("~/bundles/modernizr")' async> </script>
12</head>
استفاده از کاراکتر جایگزین «*» برای انتخاب فایل ها
مسیر مجازی مشخص شده در متد Include و الگوی جستجویی که در متد IncludeDirectoryوجود دارد، میتواند یک کاراکتر جایگزین «*» را به عنوان پیشوند یا پسوند در آخرین بخش مسیر بپذیرد.
توجه داشته باشید که رشته جستجو به بزرگ و کوچک بودن حروف حساس نیست (Case Insensitive است). این متد همچنین، امکانی برای جستجو در زیر شاخهها را دارد. پروژهای را با فایلهای جاوا اسکریپت زیر در نظر بگیرید:
- Scripts\Common\AddAltToImg.js
- Scripts\Common\ToggleDiv.js
- Scripts\Common\ToggleImg.js
- Scripts\Common\Sub1\ToggleLinks.js
جدول زیر فایلهایی را نشان میدهد که با استفاده از کاراکتر جایگزین به یک بسته اضافه شده است.
فایلهای افزوده شده یا استثناهای رخ داده | دستور فراخوانی |
AddAltToImg.js ToggleDiv.js ToggleImg.js | Include("~/Scripts/Common/*.js") |
استثنای «الگوی نامعتبر».
استفاده از کاراکتر جایگزین فقط روی پیشوند و پسوند مجاز است. | Include("~/Scripts/Common/T*.js") |
استثنای «الگوی نامعتبر».
استفاده از تنها یک کاراکتر جایگزین مجاز است. | Include("~/Scripts/Common/*og.*") |
ToggleDiv.js ToggleImg.js | Include("~/Scripts/Common/T*") |
استثنای «الگوی نامعتبر».
بخش اصلی کاراکتر معتبر نیست. | Include("~/Scripts/Common/*") |
ToggleDiv.js ToggleImg.js | IncludeDirectory("~/Scripts/Common", "T*") |
ToggleDiv.js ToggleImg.js ToggleLinks.js | IncludeDirectory("~/Scripts/Common", "T*", true) |
اختصاص هر فایل به یک باندل، نسبت به بارگذاری کاراکتر جایگزین فایلها، معمولا ترجیح داده میشود، در زیر دلایلی برای این موضوع بیان شده است:
- افزودن اسکریپتها توسط پیشفرضهایی که کاراکتر جایگزین در نظر میگیرد (برای بارگیری آنها به ترتیب حروف الفبا عمل میکند)، معمولا آن چیزی نیست که میخواهیم. فایلهای CSS و جاوا اسکریپت اغلب باید به ترتیب خاصی (غیر الفبایی) اضافه شوند. شما میتوانید این ریسک را با افزودن یک پیادهسازی سفارشی IBundleOrderer کاهش دهید. به عنوان مثال، ممکن است در آینده، assetهای جدیدی را به پوشهای اضافه کنید و نیاز باشد که پیادهسازی IBundleOrderer خود را نیز اصلاح کنید.
- فایلهای خاصی از نما، که با استفاده از بارگذاری کاراکتر جایگزین به فهرست اضافه شدهاند را میتوان در همه نماهایی که به آن بسته ارجاع میدهند اضافه کرد. اگر اسکریپت View خاصی، به یک باندل اضافه شود، ممکن است یک خطای جاوا اسکریپتی را در سایر نماهایی که به باندل ارجاع میدهند، دریافت کنید.
- فایلهای CSS که فایلهای دیگر را import میکنند، منجر به بارگذاری دوباره فایلهایی میشوند که یکبار ایمپورت شدهاند. به عنوان مثال، کدهای زیر، باندلی ایجاد میکند که اکثر فایلهای CSS قالب jQuery UI، دو مرتبه بارگذاری شدهاند.
1bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll")
2 .IncludeDirectory("~/Content/themes/base", "*.css"));
انتخابگر کاراکتر جایگزین *.css ، هر فایل CSS، از جمله فایلContent\themes\base\jquery.ui.all.cssرا به پوشه وارد میکند. فایلjquery.ui.all.cssنیز سایر فایلهای CSS را وارد میکند.
نهان سازی باندل یا Bundle Caching چیست؟
باندلها، «سرآیند» (Header) انقضای HTTP را برابر با یک سال از زمان ایجاد باندل تنظیم میکنند. با رفتن به صفحهای که قبلاً مشاهده کردهاید، Fiddler نشان میدهد که IE درخواست مشروطی را برای باندلها نمیسازد، یعنی هیچ درخواستِ HTTP GET، از IE برای باندلها و هیچ پاسخِ HTTP 304، از سمت سرور وجود ندارد.
شما با زدن کلید F5 میتوانید IE را مجبور کنید تا برای هر بسته یک درخواست شرطی ایجاد کند. (یعنی منجر به پاسخ HTTP 304 برای هر باندل شود). شما همچنین میتوانید رفرش کاملی را با کلیدهای Ctrl+F5 داشته باشید (که پاسخ HTTP 200 برای هر باندل را تولید میکند). تصویر زیر زبانه «نهانسازی» (Caching) را در صفحه پاسخ Fiddler نشان میدهد.
درخواستی که در ادامه آمده، مربوط به باندل AllMyScripts است و یک جفتِ «رشته پرس و جو» (Query String) را شامل میشود.
1http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
رشته پرس و جوی v، توکن مقداری شامل شناسهای منحصر به فرد دارد که برای نهانسازی بهکار میرود. تا زمانی که باندل تغییر نکند، برنامه ASP.NET با استفاده از این توکن، باندل AllMyScripts را درخواست میکند. هر زمانی که فایلی در باندل دچار تغییر شود، چارچوب بهینهسازی ASP.NET، توکن جدیدی ایجاد خواهد کرد و با تضمین اینکه که درخواستهای مرورگر در مورد این باندل، همیشه آخرین (جدیدترین نسخه) را دریافت میکند.
اگر Developer Tools مربوط به IE9 (کلید میانبر F12) را اجرا کنید و به صفحهای که قبلاً بارگذاری شده است بروید، IE به اشتباه درخواستهای GET مشروطی را نشان میدهد که برای هر باندل و سروری که HTTP 304 را بر میگرداند، ساخته شده است.
باندلینگ مواردی همچون LESS ،CoffeeScript ،SCSS و Sass
چارچوب باندلینگ و کمینهسازی، ساز و کاری برای پردازش زبانهای میانی مانند SCSS ،Sass ،LESS یا Coffeescript را فراهم میکند و تغییر فرمهایی (تبدیلهایی) مانند کمینهسازی در باندل به دست آمده را اعمال میکند.
برای مثال، به منظور اضافه کردن فایلهای .less به پروژه MVC خود باید موارد زیر را انجام دهیم.
- ابتدا یک پوشه برای محتوای LESS ایجاد کنید. مثالِ زیر از پوشه Content\MyLessاستفاده میکند. سپس بسته ناگت مربوط به dotless (یعنی.less) را به پروژه خود اضافه کنید.
- در ادامه، لازم است که کلاس جدیدی اضافه کنیم تا رابط IBundleTransformرا پیاده سازی کند. برای تبدیل.less، کدهای زیر را به پروژه اضافه میکنیم.
1using System.Web.Optimization;
2
3public class LessTransform : IBundleTransform
4{
5 public void Process(BundleContext context, BundleResponse response)
6 {
7 response.Content = dotless.Core.Less.Parse(response.Content);
8 response.ContentType = "text/css";
9 }
10}
- با استفاده از تبدیلهای CssMinify و LessTransform ، باندلی از فایلهای LESS ایجاد میکنیم و کد زیر به متد RegisterBundles در فایل App\_Start\BundleConfig.cs اضافه میشود.
1var lessBundle = new Bundle("~/My/Less").IncludeDirectory("~/My", "*.less");
2lessBundle.Transforms.Add(new LessTransform());
3lessBundle.Transforms.Add(new CssMinify());
4bundles.Add(lessBundle);
در پایان نیز، لازم است تا کد زیر را به همه Viewهایی اضافه کنیم که باندل LESS را فراخوانی میکنند.
1@Styles.Render("~/My/Less");
ملاحظاتی در مورد باندل ها در ASP.NET MVC
یکی از مواردی که بهتر است هنگام ایجاد باندلها رعایت شود، این است که واژه «bundle» را به عنوان پیشوند در نامگذاری آنها بهکار ببریم. این قاعده از رخ دادن «تداخل در آدرسدهی» (Routing Conflict) جلوگیری میکند.
هنگامیکه یکی از فایلهای موجود در باندل را بهروز میکنید، توکنی جدید برای پارامترِ «رشته پرس و جویِ» (Query String) باندل ایجاد میشود و دفعه بعد که کلاینت صفحه حاوی باندل را درخواست میکند، باندل باید کامل دانلود شود. در نشانهگذاری سنتی (پیش از این) که هر asset بهصورت جداگانه فهرست میشود، فقط فایل تغییر یافته دانلود میشد. بنابراین assetهایی که زود به زود تغییر میکنند ممکن است کاندیدهای مناسبی برای باندلینگ نباشند.
Bundling و Minification در ASP.NET MVC، عمدتاً زمان بارگذاری درخواست صفحه اول را بهبود میبخشند. پس از درخواست یک صفحه وب از سرور، مرورگر، assetها (جاوا اسکریپت، CSS و تصاویر) را نهانسازی میکند، بنابراین هنگام درخواست همان صفحه یا صفحاتی در همان سایت که assetهای مشابهی را درخواست میکنند، باندلینگ و کمینهسازی هیچ بهبودی را در عملکرد برنامه ایجاد نمیکنند.
اگر سرآیند مربوط به انقضا را در assetهای خود به درستی تنظیم نکنید، و همچنین از باندلینگ و کمینهسازی نیز استفاده نشود، اکتشافات مربوط به تازهسازی مرورگرها، پس از چند روز assetهای قدیمی را علامتگذاری میکنند و برای هر asset به درخواست اعتبارسنجی مجدد نیاز خواهند داشت.
محدودیت مرورگر در ۶ اتصال همزمان برای هر نام میزبان را میتوان با استفاده از CDN کاهش داد. از آنجایی که CDN، نام میزبان متفاوتی نسبت به سایت میزبان شما دارد، درخواستهای مربوط به asset از CDN، در محدودیت ۶ اتصال همزمان به محیط میزبانی شما حساب نمیشوند. یک CDN همچنین میتواند مزیتهای نهانسازی بستههای رایج و نهانسازی لبه را نیز فراهم کند.
باندلها باید بر اساس صفحاتی که به آنها نیاز دارند قسمتبندی شوند. به عنوان مثال، الگوی پیشفرض ASP.NET MVC برای یک اپلیکیشن اینترنتی، یک باندل اعتبارسنجی jQuery جدا از jQuery ایجاد میکند.
سوالات متداول
در این قسمت، تعدادی از سوالات رایج و پاسخ آنها را در پیرامون Bundling و Minification، با هم مرور میکنیم.
قابلیتهای Bundling و Minification در ASP.NET MVC را چگونه فعال کنیم؟
با تنظیم مقدار ویژگی debug در مولفه کامپایلِ موجود در فایل Web.config، میتوان این قابلیتها را فعال یا غیر فعال کرد. اگر در این فایلِ XML، ویژگی debug برابر با true باشد، باندلینگ و مینیفیکیشن، غیرفعالاند. در مقابل اگر مقدار debug برابر با false باشد، این دو ویژگی قابل استفاده هستند.
Bundling و Minification در ASP.NET MVC چه تفاوتی با هم دارند؟
تکنیکهای باندلینگ و مینیفیکیشن، با هدف بهبود عملکرد صفحات وب و افزایش سرعت بارگذاری آنها بهکار میروند. به طور خلاصه در باندلینگ، چندین فایل در قالب یک فایل با هم ادغام میشوند. مینیفیکیشن نیز بهینهسازیهایی را به منظور کمحجمتر شدن اسکریپتها و کدهای CSS، روی آنها اعمال میکند.
مزیت باندلینگ اسکریپتهای JS در قالب یک فایل چیست؟
باندلینگ جاوا اسکریپت، تکنیکی برای بهینهسازی آن است که میتواند تعداد درخواستهایی که برای دریافت این فایلها به سرور ارسال میشوند را کاهش دهد. Bundling این کار را با ادغام چندین فایل جاوا اسکریپت در قالب یک فایل، انجام میدهد تا تعداد درخواستهای صفحه کاهش پیدا کنند.
سخن پایانی
با هر نسخه جدیدی که از چارچوب ASP.NET MVC منتشر میشود، ویژگیها و امکانات بیشتر و بهتری به آن افزوده میشود. Bundling و Minification در ASP.NET MVC، فرایندهایی ضروری محسوب میشوند که باید در هر برنامه وبی که میسازیم، مورد استفاده قرار گیرند.
منظور، همان برنامههایی است که به منابع مهمی از جاوا اسکریپت و CSS متکیاند و نیاز داریم تا عملکرد بهتری را ارائه دهند. خوشبختانه، در طراحی این فرایندها، ویژگیهایی نظیر سفارشیسازی (Customization) و توسعهپذیری (Extensibility) نیز مدنظر قرار گرفته است. با کمی تلاش، Minification را نیز بر اساس اینکه برنامه وب ما در حالت دیباگ اجرا میشود یا خیر، به آسانی میتوان مورد استفاده قرار داد.