Объединение и минификация
Объединение и минификация — это два метода, которые можно использовать в ASP.NET 4.5 для увеличения времени загрузки запроса. Объединение и минификация сокращают время загрузки за счет сокращения количества запросов к серверу и уменьшения размера запрошенных ресурсов (таких как CSS и JavaScript).
Большинство текущих основных браузеров ограничивают количество одновременных подключений на каждое имя узла шестью. Это означает, что пока обрабатываются шесть запросов, дополнительные запросы на ресурсы на узле будут помещены в очередь браузером. На приведенном ниже рисунке на сетевых вкладках средств разработчика IE F12 отображается время для ресурсов, необходимых для представления О программе примера приложения.
На серых полосах отображается время постановки запроса в очередь браузером, ожидая шесть подключений. Желтая полоса — это время запроса до первого байта, то есть время, затраченное на отправку запроса и получение первого ответа от сервера. Синие полосы показывают время, затраченного на получение данных ответа от сервера. Вы можете дважды щелкнуть ресурс, чтобы получить подробные сведения о времени. Например, на следующем рисунке показаны сведения о времени загрузки файла /Scripts/MyScripts/JavaScript6.js .
На приведенном выше изображении показано событие Start , которое указывает время постановки запроса в очередь, так как браузер ограничивает количество одновременных подключений. В этом случае запрос помещался в очередь на 46 миллисекундах, ожидая завершения другого запроса.
Объединение
Объединение — это новая функция в ASP.NET 4.5, которая упрощает объединение или объединение нескольких файлов в один файл. Вы можете создавать CSS, JavaScript и другие пакеты. Чем меньше файлов, тем меньше HTTP-запросов, что может повысить производительность загрузки первой страницы.
На следующем рисунке показано то же представление времени представления О программе, показанное ранее, но на этот раз с включенным объединением и минификации.
Минификация
Минификация выполняет различные оптимизации кода для скриптов или 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/, "")) }
Помимо удаления примечаний и ненужных пробелов, следующие параметры и имена переменных были переименованы (сокращены) следующим образом:
Исходное значение | Renamed |
---|---|
imageTagAndImageID | n |
imageContext | t |
imageElement | i |
Влияние объединения и минификации
В следующей таблице показано несколько важных различий между перечислением всех ресурсов по отдельности и использованием объединения и минификации (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 Rules (Правила Fiddler) выберите Performance (Производительность ), а затем — Simulate Modem Speeds (Смоделировать скорость модема).)
Отладка пакетного и minified JavaScript
Легко выполнить отладку JavaScript в среде разработки (где элемент компиляции в файле Web.config имеет значение debug="true"
), так как файлы JavaScript не упаковываются и не миниифицируются. Вы также можете отлаживать сборку выпуска, в которой файлы JavaScript упаковываются и минимифицированы. С помощью средств разработчика IE F12 можно отлаживать функцию JavaScript, включенную в миниифицированный пакет, используя следующий подход:
- Перейдите на вкладку Скрипт и нажмите кнопку Начать отладку .
- Выберите пакет, содержащий функцию JavaScript, которую вы хотите отладить, с помощью кнопки активы.
- Отформатируйте мини-код JavaScript, нажав кнопку Конфигурация, а затем выбрав Формат JavaScript.
- В поле Входные данные Скрипт поиска выберите имя функции, которую требуется отладить. На следующем рисунке в поле входных данных Search Script введено значение AddAltToImg.
Дополнительные сведения об отладке с помощью средств разработчика F12 см. в статье MSDN Использование средств разработчика F12 для отладки ошибок JavaScript.
Управление объединением и минификации
Объединение и минификация включаются или отключается путем установки значения атрибута debug в элементе компиляции в файле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
значение или атрибут debug в элементе компиляции в файле false
Web.config , файлы не будут объединяться или миниифицироваться. Кроме того, min-версия файлов не будет использоваться, будут выбраны полные отладочные версии. EnableOptimizations
переопределяет атрибут debug в элементе compilation в файле Web.config .
Использование объединения и минификации с ASP.NET Web Forms и веб-страницами
- Сведения о веб-страницах см. в записи блога Добавление веб-оптимизации на сайт веб-страниц.
- Веб-формы см. в записи блога Добавление объединения и минификации в веб-формы.
Использование объединения и минификации с 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, соответствующие строке wild карта "~/Scripts/jquery-{version}.js". Для ASP.NET MVC 4 это означает, что в конфигурации отладки файлjquery-1.7.1.js будет добавлен в пакет. В конфигурации выпуска будут добавленыjquery-1.7.1.min.js . Структура объединения соответствует нескольким общим соглашениям, таким как:
- Если FileX.min.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
Bundle показан ниже:
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 принимают массив строк, поэтому вы можете добавить несколько пакетов в одну строку кода. Обычно требуется использовать методы 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:
- Scripts\Common\AddAltToImg.js
- Scripts\Common\ToggleDiv.js
- Scripts\Common\ToggleImg.js
- Scripts\Common\Sub1\ToggleLinks.js
В следующей таблице показаны файлы, добавленные в пакет с помощью подстановочного знака, как показано ниже.
Вызов | Добавленные файлы или возникает исключение |
---|---|
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 .
Просмотр определенных файлов, добавленных в каталог с помощью wild карта загрузка может быть включена во все представления, ссылающиеся на этот пакет. Если скрипт для определенного представления добавляется в пакет, в других представлениях, ссылающихся на пакет, может возникнуть ошибка JavaScript.
Css-файлы, которые импортируют другие файлы, приводят к тому, что импортированные файлы загружаются дважды. Например, следующий код создает пакет с большинством CSS-файлов темы jQuery UI, загруженных дважды.
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 Expires через год с момента создания пакета. При переходе на ранее просмотренную страницу 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 создаст новый токен, гарантируя, что запросы браузера для пакета получат последнюю версию пакета.
Если вы запускаете средства разработчика F12 IE9 и переходите на ранее загруженную страницу, IE неправильно отображает условные запросы GET, выполненные к каждому пакету и серверу, возвращающим HTTP 304. Вы можете узнать, почему в IE9 возникают проблемы с определением того, был ли выполнен условный запрос, в записи блога Использование CDN и Истекает для повышения производительности веб-сайта.
LESS, CoffeeScript, SCSS, Sass Bundling.
Платформа объединения и минификации предоставляет механизм для обработки промежуточных языков, таких как SCSS, Sass, LESS или Coffeescript, и применения преобразований, таких как минификация, к полученному пакету. Например, чтобы добавить less-файлы в проект MVC 4, выполните приведенные ниже действия.
Создайте папку для содержимого LESS. В следующем примере используется папка Content\MyLess .
Добавьте в проект пакет NuGet .less.
Добавьте класс, реализующий интерфейс 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");
Рекомендации по пакету
При создании пакетов рекомендуется включить слово "bundle" в качестве префикса в имя пакета. Это предотвратит возможный конфликт маршрутизации.
После обновления одного файла в пакете для параметра строки запроса пакета создается новый маркер, и при следующем запросе клиентом страницы, содержащей пакет, необходимо скачать полный пакет. В традиционной разметке, где каждый ресурс указан по отдельности, будет скачан только измененный файл. Ресурсы, которые часто изменяются, могут быть не очень хорошими кандидатами для объединения.
Объединение и минификация в первую очередь ускоряют загрузку первой страницы. После запроса веб-страницы браузер кэширует ресурсы (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
Дополнительные ресурсы
- Видео:Объединение и оптимизацияГовард Диркинг
- Добавление веб-оптимизации на сайт веб-страниц.
- Добавление объединения и минификации в веб-формы.
- Влияние на производительность объединения и минификации при просмотре веб-страницХенрик Ф. Нильсен@frystyk
- Использование CDN и expires для повышения производительности веб-сайта Рик Андерсон @RickAndMSFT
- Минимизация rtt (время кругового пути)
Соавторы
- Хао Кунг
- Говард Диркинг
- Диана ЛаРоуз
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по