Объединение и минификация
Объединение и минификации — это два метода, которые можно использовать в ASP.NET 4.5 для улучшения времени загрузки запроса. Объединение и минификации повышают время загрузки, уменьшая количество запросов к серверу и уменьшая размер запрошенных ресурсов (например, CSS и JavaScript.)
Большинство текущих основных браузеров ограничивают количество одновременных подключений на каждое имя узла до шести. Это означает, что в то время как обрабатываются шесть запросов, дополнительные запросы ресурсов на узле будут помещены в очередь в браузере. На рисунке ниже на сетевых вкладках средств разработчика IE F12 отображаются сроки использования ресурсов, необходимых для представления примера приложения.
Серые полосы показывают время, когда запрос помещается в очередь браузером, ожидая шести ограничений подключения. Желтая полоса — это время запроса на первый байт, то есть время, необходимое для отправки запроса и получение первого ответа от сервера. Синие полосы показывают время, необходимое для получения данных ответа от сервера. Вы можете дважды щелкнуть ресурс, чтобы получить подробные сведения о времени. Например, на следующем рисунке показаны сведения о времени загрузки файла /Scripts/MyScripts/JavaScript6.js .
На приведенном выше рисунке показано событие Start , которое дает время, когда запрос был помещен в очередь из-за ограничения количества одновременных подключений в браузере. В этом случае запрос был помещен в очередь в 46 миллисекундах, ожидающих завершения другого запроса.
Объединение
Объединение — это новая функция в ASP.NET 4.5, которая упрощает объединение или объединение нескольких файлов в один файл. Вы можете создать CSS, JavaScript и другие пакеты. Меньше файлов означает меньше HTTP-запросов, что может повысить производительность первой страницы.
На следующем рисунке показан тот же режим времени, что и представление "Сведения", показанное ранее, но на этот раз с включенным объединением и минификации.
Минификация
Minification выполняет различные оптимизации кода для скриптов или css, таких как удаление ненужных пробелов и комментариев и сокращение имен переменных до одного символа. Рассмотрим следующую функцию JavaScript.
AddAltToImg = function (imageTagAndImageID, imageContext) {
///<signature>
///<summary> Adds an alt tab to the image
// </summary>
//<param name="imgElement" type="String">The image selector.</param>
//<param name="ContextForImage" type="String">The image context.</param>
///</signature>
var imageElement = $(imageTagAndImageID, imageContext);
imageElement.attr('alt', imageElement.attr('id').replace(/ID/, ''));
}
После минификации функция уменьшается до следующего:
AddAltToImg = function (n, t) { var i = $(n, t); i.attr("alt", i.attr("id").replace(/ID/, "")) }
Помимо удаления комментариев и ненужных пробелов, следующие параметры и имена переменных были переименованы (сокращены) следующим образом:
Исходное значение | Переименован |
---|---|
imageTagAndImageID | n |
imageContext | t |
imageElement | i |
Влияние бундлинга и минификации
В следующей таблице показано несколько важных различий между перечислением всех активов по отдельности и использованием объединением и минификации (B/M) в примере программы.
Использование B/M | Без B/M | Изменение | |
---|---|---|---|
Запросы файлов | 9 | 34 | 256% |
База знаний отправлена | 3.26 | 11.92 | 266% |
Полученная база знаний | 388.51 | 530 | 36 % |
Время загрузки | 510 МС | 780 МС | 53 % |
Отправленные байты имели значительное сокращение с объединением, так как браузеры довольно подробно с заголовками HTTP, которые они применяются к запросам. Сокращение полученных байтов не так велико, так как уже минуются самые большие файлы (Scripts\jquery-ui-1.8.11.min.js и Scripts\jquery-1.7.1.min.js). Примечание. Время в примере программы использовало средство Fiddler для имитации медленной сети. (Из Fiddler Меню правил выберите "Производительность", а затем "Имитация скоростей модема".)
Отладка пакета и minified JavaScript
Легко выполнить отладку JavaScript в среде разработки (где для элемента компиляции в файле конфигурации Web.config задано значение debug="true"
), так как файлы JavaScript не упаковываются или не минируются. Вы также можете выполнить отладку сборки выпуска, в которой файлы JavaScript упаковываются и минируются. С помощью средств разработчика IE F12 выполняется отладка функции JavaScript, включенной в минифицированный пакет, с помощью следующего подхода:
- Перейдите на вкладку "Скрипт" и нажмите кнопку "Начать отладку ".
- Выберите пакет, содержащий функцию JavaScript, которую вы хотите выполнить отладку с помощью кнопки ресурсов.
- Отформатируйте мини-код JavaScript, нажав кнопку "Конфигурация", а затем выберите формат JavaScript.
- В поле ввода скрипта поиска выберите имя функции, которую требуется выполнить отладку. На следующем рисунке в поле ввода скрипта поиска ввели AddAltToImg.
Дополнительные сведения об отладке с помощью средств разработчика F12 см. в статье MSDN с помощью средств разработчика F12 для отладки ошибок JavaScript.
Управление объединением и минификации
Объединение и минификации включено или отключено, задав значение атрибута отладки в элементе компиляции в файле web.config. В следующем XML задано значение true, debug
поэтому объединение и минификации отключены.
<system.web>
<compilation debug="true" />
<!-- Lines removed for clarity. -->
</system.web>
Чтобы включить объединение и минификации, задайте debug
значение false. Параметр web.config можно переопределить свойством EnableOptimizations
классаBundleTable
. Следующий код включает объединение и минификации и переопределяет любой параметр в файле конфигурации Web.config .
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
BundleTable.EnableOptimizations = true;
}
Примечание.
Если EnableOptimizations
true
атрибут отладки в элементе компиляции в файле конфигурации Web.config не заданfalse
, файлы не будут упаковываться или минироваться. Кроме того, не будет использоваться минимальная версия файлов, будут выбраны полные отладочные версии. EnableOptimizations
переопределяет атрибут отладки в элементе компиляции в файле web.config
Использование Bundling и Minification с ASP.NET веб-формы и веб-страницами
- Сведения о веб-страницах см. в записи блога о добавлении веб-оптимизации на сайт веб-страниц.
- Сведения о веб-формы см. в записи блога о добавлении bundling и Minification в веб-формы.
Использование Bundling и Minification с ASP.NET MVC
В этом разделе мы создадим проект ASP.NET MVC для изучения избыточности и минификации. Сначала создайте новый ASP.NET интернет-проект MVC с именем MvcBM , не изменяя значения по умолчанию.
Откройте файл App\_Start\BundleConfig.cs и проверьте RegisterBundles
метод, используемый для создания, регистрации и настройки пакетов. В следующем коде показана часть RegisterBundles
метода.
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
Предыдущий код создает новый пакет JavaScript с именем ~/bundles/jquery , который включает все соответствующие (то есть отладочные или минифицированные, но нет.vsdoc) файлы в папке "Скрипты", которая соответствует строке подстановочной карточки "~/Scripts/jquery-{version}.js". Для ASP.NET MVC 4 это означает, что конфигурация отладки будет добавлена в пакет jquery-1.7.1.js файла. В конфигурации выпуска jquery-1.7.1.min.js будет добавлен. Платформа объединение следует нескольким общим соглашениям, таким как:
- Если FileX.min.js и FileX.js существуют FileX.js, выберите файл .min для выпуска.
- Выбор версии, отличной от ".min", для отладки.
- Игнорируя файлы "-vsdoc" (например , jquery-1.7.1-vsdoc.js), которые используются только IntelliSense.
Сопоставление {version}
с подстановочными карточками, показанное выше, используется для автоматического создания пакета jQuery с соответствующей версией jQuery в папке Scripts . В этом примере использование подстановочной карты обеспечивает следующие преимущества:
- Позволяет использовать NuGet для обновления до более новой версии jQuery, не изменяя предыдущий код или ссылки jQuery на страницах представления.
- Автоматически выбирает полную версию для конфигураций отладки и версию min для сборок выпуска.
Использование CDN
Следующий код заменяет локальный пакет jQuery пакетом CDN jQuery.
public static void RegisterBundles(BundleCollection bundles)
{
//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js"));
bundles.UseCdn = true; //enable CDN support
//add link to jquery on the CDN
var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery",
jqueryCdnPath).Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
В приведенном выше коде jQuery будет запрашиваться из CDN в режиме выпуска, а отладочная версия jQuery будет получена локально в режиме отладки. При использовании CDN необходимо иметь резервный механизм в случае сбоя запроса CDN. Следующий фрагмент разметки из конца файла макета показывает скрипт, добавленный для запроса jQuery, если CDN завершится ошибкой.
</footer>
@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>
@RenderSection("scripts", required: false)
</body>
</html>
Создание пакета
Метод класса Include
Bundle принимает массив строк, где каждая строка — это виртуальный путь к ресурсу. Следующий код из RegisterBundles
метода в файле App\_Start\BundleConfig.cs показывает, как несколько файлов добавляются в пакет:
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"));
Метод класса IncludeDirectory
Bundle предоставляется для добавления всех файлов в каталог (и при необходимости всех подкаталогов), которые соответствуют шаблону поиска. API класса IncludeDirectory
пакета показан ниже:
public Bundle IncludeDirectory(
string directoryVirtualPath, // The Virtual Path for the directory.
string searchPattern) // The search pattern.
public Bundle IncludeDirectory(
string directoryVirtualPath, // The Virtual Path for the directory.
string searchPattern, // The search pattern.
bool searchSubdirectories) // true to search subdirectories.
Пакеты ссылаются в представлениях с помощью метода Render (Styles.Render
для CSS и Scripts.Render
JavaScript). Следующая разметка из файла Views\Shared\_Layout.cshtml показывает, как ASP.NET представления проекта Интернета по умолчанию ссылались на пакеты CSS и JavaScript.
<!DOCTYPE html>
<html lang="en">
<head>
@* Markup removed for clarity.*@
@Styles.Render("~/Content/themes/base/css", "~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@* Markup removed for clarity.*@
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
Обратите внимание, что методы render принимают массив строк, поэтому можно добавить несколько пакетов в одну строку кода. Как правило, вы хотите использовать методы отрисовки, которые создают необходимый HTML-код для ссылки на ресурс. Метод можно использовать Url
для создания URL-адреса ресурса без разметки, необходимой для ссылки на ресурс. Предположим, вы хотите использовать новый асинхронный атрибут HTML5. В следующем коде показано, как ссылаться на модернизатор с помощью Url
метода.
<head>
@*Markup removed for clarity*@
<meta charset="utf-8" />
<title>@ViewBag.Title - MVC 4 B/M</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@* @Scripts.Render("~/bundles/modernizr")*@
<script src='@Scripts.Url("~/bundles/modernizr")' async> </script>
</head>
Использование подстановочного знака "*" для выбора файлов
Виртуальный путь, указанный в методе Include
, и шаблон поиска в методе IncludeDirectory
может принимать один подстановочный знак "*" в качестве префикса или суффикса в последнем сегменте пути. Строка поиска не учитывает регистр. Метод IncludeDirectory
имеет возможность поиска подкаталогов.
Рассмотрим проект со следующими файлами JavaScript:
- Скрипты\Common\AddAltToImg.js
- Скрипты\Common\ToggleDiv.js
- Скрипты\Common\ToggleImg.js
- Скрипты\Common\Sub1\ToggleLinks.js
В следующей таблице показаны файлы, добавленные в пакет, с помощью подстановочного знака, как показано ниже.
Call | Добавленные или исключения файлов |
---|---|
Include("~/Scripts/Common/*.js") | AddAltToImg.js, ToggleDiv.js, ToggleImg.js |
Include("~/Scripts/Common/T*.js") | Недопустимое исключение шаблона. Подстановочный знак разрешен только в префиксе или суффиксе. |
Include("~/Scripts/Common/*og.*") | Недопустимое исключение шаблона. Допускается только один подстановочный знак. |
Include("~/Scripts/Common/T*") | ToggleDiv.js, ToggleImg.js |
Include("~/Scripts/Common/*") | Недопустимое исключение шаблона. Недопустимый сегмент чистого подстановочного знака. |
IncludeDirectory("~/Scripts/Common", "T*") | ToggleDiv.js, ToggleImg.js |
IncludeDirectory("~/Scripts/Common", "T*", true) | ToggleDiv.js, ToggleImg.js, ToggleLinks.js |
Явное добавление каждого файла в пакет обычно предпочтительнее при загрузке подстановочных знаков по следующим причинам:
Добавление скриптов по подстановочным знакам по умолчанию для их загрузки в алфавитном порядке, которое обычно не является нужным. Файлы CSS и JavaScript часто необходимо добавлять в определенный (не алфавитный) порядок. Вы можете устранить этот риск, добавив пользовательскую реализацию IBundleOrderer , но явно добавляя каждый файл, менее подвержены ошибкам. Например, вы можете добавить новые ресурсы в папку в будущем, что может потребовать изменения реализации IBundleOrderer .
Просмотр определенных файлов, добавленных в каталог с помощью загрузки подстановочных карт, можно включить во все представления, ссылающиеся на этот пакет. Если в пакет добавляется определенный скрипт представления, может появиться ошибка JavaScript в других представлениях, ссылающихся на пакет.
CSS-файлы, импортированные другие файлы, приводят к тому, что импортированные файлы загружаются дважды. Например, следующий код создает пакет с большинством css-файлов темы пользовательского интерфейса jQuery, загруженных дважды.
bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll") .IncludeDirectory("~/Content/themes/base", "*.css"));
Селектор подстановочной карточки "*.css" содержит каждый CSS-файл в папке, включая файл Content\themes\base\jquery.ui.all.css . Файл jquery.ui.all.css импортирует другие CSS-файлы.
Кэширование пакетов
Пакеты задают заголовок HTTP С истекает годом после создания пакета. Если вы перейдете на ранее просматриваемую страницу, Fiddler показывает, что IE не выполняет условный запрос для пакета, то есть нет HTTP-запросов GET из IE для пакетов и нет ответов HTTP 304 с сервера. Вы можете принудительно отправить IE условный запрос для каждого пакета с ключом F5 (в результате чего ответ HTTP 304 для каждого пакета). Вы можете принудительно выполнить полное обновление с помощью ^F5 (в результате ответа HTTP 200 для каждого пакета).)
На следующем рисунке показана вкладка кэширования области ответов Fiddler:
Запрос
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
предназначен для пакета AllMyScripts и содержит пару строк запроса v=r0sLDicvP58AIXN\_mc3QdyVvVj5euZNzdsa2N1PKvb81. Строка запроса v имеет маркер значения, который является уникальным идентификатором, используемым для кэширования. Пока пакет не изменится, приложение ASP.NET запросит пакет AllMyScripts с помощью этого маркера. Если любой файл в пакете изменяется, платформа оптимизации ASP.NET создаст новый маркер, гарантируя, что запросы браузера для пакета получат последний пакет.
Если вы запускаете средства разработчика IE9 F12 и переходите на ранее загруженную страницу, IE неправильно отображает условные запросы GET, сделанные для каждого пакета, и сервер, возвращающий HTTP 304. Вы можете прочитать, почему IE9 имеет проблемы, определяющие, был ли условный запрос сделан в записи блога с помощью CDN и истекает срок действия для повышения производительности веб-сайта.
LESS, CoffeeScript, SCSS, Sass Bundling.
Платформа bundling и minification предоставляет механизм обработки промежуточных языков, таких как SCSS, Sass, LESS или Coffeescript, и применение преобразований, таких как минификации к результирующему пакету. Например, чтобы добавить В проект MVC 4 файлы меньшего размера, выполните приведенные ниже действия.
Создайте папку для содержимого LESS. В следующем примере используется папка Content\MyLess .
Добавьте в проект пакет NuGet с меньшей точкой.
Добавьте класс, реализующий интерфейс IBundleTransform . Для преобразования .less добавьте следующий код в проект.
using System.Web.Optimization; public class LessTransform : IBundleTransform { public void Process(BundleContext context, BundleResponse response) { response.Content = dotless.Core.Less.Parse(response.Content); response.ContentType = "text/css"; } }
Создайте пакет ФАЙЛОВ LESS с
LessTransform
преобразованием CssMinify . Добавьте следующий код вRegisterBundles
метод в файле App\_Start\BundleConfig.cs .var lessBundle = new Bundle("~/My/Less").IncludeDirectory("~/My", "*.less"); lessBundle.Transforms.Add(new LessTransform()); lessBundle.Transforms.Add(new CssMinify()); bundles.Add(lessBundle);
Добавьте следующий код в любые представления, ссылающиеся на пакет LESS.
@Styles.Render("~/My/Less");
Рекомендации по пакету
Хорошее соглашение, чтобы следовать при создании пакетов, заключается в том, чтобы включить "пакет" в качестве префикса в имя пакета. Это позволит предотвратить возможный конфликт маршрутизации.
После обновления одного файла в пакете создается новый маркер для параметра строки запроса пакета, а полный пакет должен быть скачан при следующем запросе клиента на страницу, содержащую пакет. В традиционной разметке, в которой каждый ресурс указан по отдельности, будет скачан только измененный файл. Ресурсы, которые часто изменяются, могут не быть хорошими кандидатами на объединение.
Объединение и минификация в первую очередь ускоряют загрузку первой страницы. После запроса веб-страницы браузер кэширует ресурсы (JavaScript, CSS и изображения), поэтому объединение и минификации не будет обеспечивать повышение производительности при запросе той же страницы или страниц на том же сайте, запрашивая те же ресурсы. Если срок действия заголовка истекает правильно в ресурсах, и вы не используете объединение и минификации, браузеры свежести эвристики помечают ресурсы устаревшими через несколько дней, и браузеру потребуется запрос проверки для каждого ресурса. В этом случае объединение и минификации обеспечивают увеличение производительности после первого запроса страницы. Дополнительные сведения см. в блоге с использованием CDN и истекает срок действия для повышения производительности веб-сайта.
Ограничение браузера для каждого имени узла может быть устранено с помощью CDN. Так как CDN будет иметь другое имя узла, чем сайт размещения, запросы ресурсов из CDN не будут учитываться в отношении шести одновременных подключений к вашей среде размещения. CDN также может предоставлять общие преимущества кэширования пакетов и пограничных кэширований.
Пакеты должны быть секционированы по страницам, которым они нужны. Например, шаблон по умолчанию ASP.NET MVC для интернет-приложения создает пакет проверки jQuery отдельно от jQuery. Так как созданные по умолчанию представления не имеют входных данных и не публикуют значения, они не включают пакет проверки.
Пространство System.Web.Optimization
имен реализуется в System.Web.Optimization.dll. Она использует библиотеку WebGrease (WebGrease.dll) для возможностей минификации, которые, в свою очередь, используют Antlr3.Runtime.dll.
Я использую Twitter, чтобы сделать быстрые записи и поделиться ссылками. Мой дескриптор Twitter: @RickAndMSFT
Дополнительные ресурсы
- Видео:Объединение и оптимизация Говард Диркинг
- Добавление веб-оптимизации на сайт веб-страниц.
- Добавление Bundling и Minification в веб-формы.
- Последствия производительности bundling и Minification на веб-просмотре Хенрик Ф Nielsen @frystyk
- Использование CDN и истекает срок действия для повышения производительности веб-сайта Рик Андерсон @RickAndMSFT
- Свести к минимуму RTT (время кругового пути)
Соавторы
- Хао Кунг
- Говард Диркинг
- Диана ЛаРосе