- PVSM.RU - https://www.pvsm.ru -
В начале 2012 года я работал над серией статей о клиентской оптимизации в ASP.NET MVC для журнала MSDeveloper.RU. Всего было опубликовано 2 статьи: «Сжатие JS- и CSS-файлов» [1] и «Менеджеры ресурсов» [2], но в моих планах было написать еще 2 статьи: одну про оптимизацию графики, а вторую про минимизацию HTML-разметки и GZIP/Deflate-сжатие (далее просто HTTP-сжатие). К сожалению, эти планы не удалось воплотить в жизнь из-за нехватки свободного времени (в тот момент, я запускал проект Bundle Transformer [3]) и последовавшего закрытия журнала.
Но недавно я решил вернуться к теме оптимизации HTML-разметки. После небольшого исследования я понял, что под .NET практически не существует полноценных HTML-минимизаторов. Все существующие .NET-решения производят лишь 2 операции: удаление ненужных пробельных символов и удаление HTML-комментариев, из-за чего они очень сильно проигрывают решениям с других платформ. Поэтому я решил написать собственный HTML-минимизатор для .NET, о котором и пойдет речь в данной статье.
Прежде чем приступить к описанию своего проекта, я хотел бы немного рассказать о почти 15-летней истории HTML-минимизации и эволюции программный средств, автоматизирующих данный процесс.
Вопреки расхожему мнению, техники минимизации HTML-кода появились намного раньше, чем аналогичные техники для JavaScript. Уже в конце 1998 года Артемий Лебедев в 17-м параграфе ководства «Паранойя оптимизатора» [4] описывал некоторые техники минимизации HTML-кода.
К началу 2000-х уже были известны многие техники минимизации HTML, которые актуальны и по сей день:
</p>
и </li>
)Но также получили широкое распространение и опасные техники, которые могут приводить к неправильному отображению документа и нарушению его семантики:
<!DOCTYPE …>
<strong>
заменялись на <b>
, а <em>
на <i>
)В это же время появились первые HTML-минимизаторы. Только под ОС Windows существовало около десятка бесплатных и условно-бесплатных программ: HTML Shrinker [5], Absolute HTML Compressor [6], Оптимизатор HTML файлов, HTML Source Cleaner, Anetto HTML Optimize!, HTMLCompact, HTML Code Cleaner [7], HTMLOpt [8], Absolute HTML Optimizer и др.
Рис. 1. Оптимизатор HTML файлов 1.1.0 – типичный HTML-минимизатор начала 2000-х
К середине 2000-х широкое распространение получил стандарт XHTML, который требовал написания HTML-кода в соответствии с синтаксическими правилами XML. Эти правила запрещали удаление ненужных кавычек из атрибутов и удаление необязательных конечных тегов. Таким образом, строгие правила XHTML и постоянно растущая пропускная способность привели к тому, что потребность в минимизации HTML-разметки постепенно отпала.
Но несколько лет назад из-за роста мобильного веба и появления стандарта HTML5 вновь возникла потребность в минимизации HTML-разметки. Стандарт HTML5 предоставляет гораздо больше возможностей для сокращения размера HTML-документа, чем HTML 4.01. Многие новые техники минимизации хорошо описаны в руководстве по оформлению HTML/CSS кода от Google [9] и статье Юрия Зайцева «Optimizing HTML» [10].
Все это привело к появлению новых мощных HTML-минимизаторов, ориентированных на HTML5. На данный момент наибольшую популярность получили 2 минимизатора: HtmlCompressor [11] Сергея Ковальчука (написан на Java) и Experimental HTML Minifier [12] Юрия Зайцева (написан на JavaScript).
При создании Web Markup Minifier (сокращенно WebMarkupMin) я поставил себе задачу, создать современный HTML-минимизатор для платформы .NET и расширения для его интеграции с ASP.NET. WebMarkupMin — это Open Source-проект, исходный код которого опубликован на сайте CodePlex [13], а дистрибутивы можно загрузить через NuGet [14].
Помимо HTML-минимизатора в рамках проекта WebMarkupMin были также реализованы XHTML- и XML-минимизатор. Поскольку данная статья посвящена HTML-минимизации, то в ней будут приводиться только примеры работы с HTML-минимизатором.
Проект имеет следующую структуру:
Модуль WebMarkupMin.Core – это библиотека под .NET Framework 4.0, которая содержит инструменты для минимизации разметки. Данную библиотеку можно использовать в различных типах .NET-приложений: ASP.NET, Windows Forms, WPF и консольных приложениях. Поскольку все минимизаторы разметки поддерживают не только минимизацию документов, но и минимизацию отдельных фрагментов кода, то вы можете использовать WebMarkupMin для минимизации отдельных блоков контента (например, производить минимизацию текста статьи, при ее сохранении в административной части вашего сайта).
Модуль WebMarkupMin.Core содержит 3 минимизатора разметки:
Рассмотрим простейший пример использования класса HtmlMinifier
:
namespace WebMarkupMin.Example.Console
{
using System;
using System.Collections.Generic;
using WebMarkupMin.Core;
using WebMarkupMin.Core.Minifiers;
using WebMarkupMin.Core.Settings;
class Program
{
static void Main(string[] args)
{
const string htmlInput = @"<!DOCTYPE html>
<html>
<head>
<meta charset=""utf-8"" />
<title>Тестовый документ</title>
<link href=""favicon.ico"" rel=""shortcut icon"" type=""image/x-icon"" />
<meta name=""viewport"" content=""width=device-width"" />
<link rel=""stylesheet"" type=""text/css"" href=""/Content/Site.css"" />
</head>
<body>
<p>Какой-то текст…</p>
<script src=""http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js""></script>
<script>(window.jquery) || document.write('<script src=""/Scripts/jquery-1.9.1.min.js""></script>');</script>
</body>
</html>";
var settings = new HtmlMinificationSettings
{
WhitespaceMinificationMode = WhitespaceMinificationMode.Aggressive,
RemoveHttpProtocolFromAttributes = true,
RemoveHttpsProtocolFromAttributes = true
};
var htmlMinifier = new HtmlMinifier(settings);
MarkupMinificationResult result = htmlMinifier.Minify(htmlInput,
generateStatistics: true);
if (result.Errors.Count == 0)
{
MinificationStatistics statistics = result.Statistics;
if (statistics != null)
{
Console.WriteLine("Размер до минимизации: {0:N0} байт",
statistics.OriginalSize);
Console.WriteLine("Размер после минимизации: {0:N0} байт",
statistics.MinifiedSize);
Console.WriteLine("Экономия: {0:N2}%",
statistics.SavedInPercent);
}
Console.WriteLine("Минимизированный код:{0}{0}{1}",
Environment.NewLine, result.MinifiedContent);
}
else
{
IList<MinificationErrorInfo> errors = result.Errors;
Console.WriteLine("Найдено {0:N0} ошибок:", errors.Count);
Console.WriteLine();
foreach (var error in errors)
{
Console.WriteLine("Строка {0}, Столбец {1}: {2}",
error.LineNumber, error.ColumnNumber, error.Message);
Console.WriteLine();
}
}
}
}
}
Сначала мы создаем экземпляр класса HtmlMinificationSettings
и переопределяем некоторые параметры HTML-минимизации. Затем передаем его в экземпляр класса HtmlMinifier
через соответствующий параметр конструктора, после чего вызываем метод Minify
со следующими параметрами: первый параметр содержит HTML-код, а второй – признак разрешающий генерацию статистической информации (значение по умолчанию – false, т.к. генерация статистики требует времени и дополнительных ресурсов сервера). Метод Minify
возвращает объект типа MarkupMinificationResult
, который имеет следующие свойства:
Если список ошибок пуст, то на консоль выводятся статистические данные и минимизированный код; в обратном случае выводится информация об ошибках.
А теперь подробно рассмотрим свойства класса HtmlMinificationSettings
:
Табл. 1. Свойства класса HtmlMinificationSettings
Свойство | Тип данных | Значение по умолчанию | Описание |
---|---|---|---|
WhitespaceMinificationMode |
Перечисление | Medium |
Режим минимизации пробельных символов. Может принимать следующие значения:
|
RemoveHtmlComments |
Булевский | true |
Флаг, отвечающий за удаление всех HTML-комментариев, за исключением условных комментариев Internet Explorer и noindex . |
RemoveHtmlCommentsFromScriptsAndStyles |
Булевский | true |
Флаг, отвечающий за удаление HTML-комментариев из тегов script и style . |
RemoveCdataSectionsFromScriptsAndStyles |
Булевский | true |
Флаг, отвечающий за удаление секций CDATA из тегов script и style . |
UseShortDoctype |
Булевский | true |
Флаг, отвечающий за замену существующей декларации doctype на более короткую <!DOCTYPE html> . |
UseMetaCharsetTag |
Булевский | true |
Флаг, отвечающий за замену тега <meta http-equiv="content-type" content="text/html; charset=…"> на тег <meta charset="…"> . |
EmptyTagRenderMode |
Перечисление | NoSlash |
Режим рендеринга пустых тегов. Может принимать следующие значения:
|
RemoveOptionalEndTags |
Булевский | true |
Флаг, отвечающий за удаление необязательных конечных тегов (html , head , body , p , li , dt , dd , rt , rp , optgroup , option , colgroup , thead , tfoot , tbody , tr , th и td ). |
RemoveTagsWithoutContent |
Булевский | false |
Флаг, отвечающий за удаление тегов, имеющий пустое содержимое, за исключением тегов textarea , tr , th , td , и тегов с атрибутами class , id , name , role , src и data-* . |
CollapseBooleanAttributes |
Булевский | true |
Флаг, отвечающий за «сворачивание» булевых атрибутов (например, checked="checked" сокращается до checked ). |
RemoveEmptyAttributes |
Булевский | true |
Флаг, отвечающий за удаление пустых атрибутов (применяется только к следующим атрибутам: class , id , name , style , title , lang , dir , событийным атрибутам, атрибуту action тега form и атрибуту value тега input ). |
AttributeQuotesRemovalMode |
Перечисление | Html5 |
Режим удаления кавычек в HTML-атрибутах. Может принимать следующие значения:
|
RemoveRedundantAttributes |
Булевский | true |
Флаг, отвечающий за удаление избыточных атрибутов:
|
RemoveJsTypeAttributes |
Булевский | true |
Флаг, отвечающий за удаление атрибутов type="text/javascript" из тегов script . |
RemoveCssTypeAttributes |
Булевский | true |
Флаг, отвечающий за удаление атрибутов type="text/css" из тегов style и link . |
RemoveHttpProtocolFromAttributes |
Булевский | false |
Флаг, отвечающий за удаление префикса протокола HTTP (http: ) из атрибутов, которые содержат URL (теги, помеченные атрибутом rel="external" игнорируются). |
RemoveHttpsProtocolFromAttributes |
Булевский | false |
Флаг, отвечающий за удаление префикса протокола HTTPS (https: ) из атрибутов, которые содержат URL (теги, помеченные атрибутом rel="external" игнорируются). |
RemoveJsProtocolFromAttributes |
Булевский | true |
Флаг, отвечающий за удаление префикса псевдо-протокола javascript: из событийных атрибутов. |
MinifyEmbeddedCssCode |
Булевский | true |
Флаг, отвечающий за минимизацию CSS-кода в тегах style . |
MinifyInlineCssCode |
Булевский | true |
Флаг, отвечающий за минимизацию CSS-кода в атрибутах style . |
MinifyEmbeddedJsCode |
Булевский | true |
Флаг, отвечающий за минимизацию JS-кода в тегах script . |
MinifyInlineJsCode |
Булевский | true |
Флаг, отвечающий за минимизацию JS-кода в событийных атрибутах и гиперссылках с псевдо-протоколом javascript: . |
Если в разных частях вашего приложения требуются одинаковые параметры HTML-минимизации, то вы можете указать их всего один раз в конфигурационном файле (App.config
или Web.config
) в элементе /configuration/webMarkupMin/core/html
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="webMarkupMin">
<section name="core"
type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
…
</sectionGroup>
…
</configSections>
…
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<core>
<html whitespaceMinificationMode="Medium" removeHtmlComments="true"
removeHtmlCommentsFromScriptsAndStyles="true"
removeCdataSectionsFromScriptsAndStyles="true"
useShortDoctype="true" useMetaCharsetTag="true"
emptyTagRenderMode="NoSlash" removeOptionalEndTags="true"
removeTagsWithoutContent="false" collapseBooleanAttributes="true"
removeEmptyAttributes="true"
attributeQuotesRemovalMode="Html5" removeRedundantAttributes="true"
removeJsTypeAttributes="true" removeCssTypeAttributes="true"
removeHttpProtocolFromAttributes="false"
removeHttpsProtocolFromAttributes="false"
removeJsProtocolFromAttributes="true"
minifyEmbeddedCssCode="true" minifyInlineCssCode="true"
minifyEmbeddedJsCode="true" minifyInlineJsCode="true" />
…
</core>
…
</webMarkupMin>
…
</configuration>
Чтобы получить экземпляр класса HtmlMinificationSettings
со значениями из конфигурационного файла, используйте следующий код:
HtmlMinificationSettings settings = WebMarkupMinContext.Current.Markup.GetHtmlMinificationSettings();
Также вы можете создать экземпляр класса HtmlMinifier
, который будет использовать настройки указанные в конфигурационном файле (параметры HTML-минимизации, а также зарегистрированные по умолчанию: CSS-минимизатор, JS-минимизатор и логгер):
HtmlMinifier htmlMinifier = WebMarkupMinContext.Current.Markup.CreateHtmlMinifierInstance();
Данный способ создания экземпляра HTML-минимизатора используется во всех модулях, отвечающих за интеграцию с ASP.NET.
HtmlMinifier
и XhtmlMinifier
помимо минимизации разметки поддерживают: минимизацию CSS-кода в тегах и атрибутах style
, и минимизацию JavaScript-кода в тегах script
, событийных атрибутах (например, onclick
) и гиперссылках с псевдо-протоколом javascript:
.
Минимизация CSS- и JS-кода производится классами, реализующими интерфейсы ICssMinifier
и IJsMinifier
из пространства имен WebMarkupMin.Core.Minifiers
.
Ядро содержит два класса, которые реализуют интерфейс ICssMinifier
:
И два класса, которые реализуют интерфейс IJsMinifier
:
Экземпляры CSS- и JS-минимизаторов могут быть переданы в минимизатор разметки через его конструктор:
var kristensenCssMinifier = new KristensenCssMinifier();
var crockfordJsMinifier = new CrockfordJsMinifier();
var htmlMinifier = new HtmlMinifier(cssMinifier: kristensenCssMinifier,
jsMinifier: crockfordJsMinifier);
Если минимизатор разметки создается на основе параметров конфигурационного файла, то CSS- и JS-минимизаторы можно передать в минимизатор разметки путем регистрации их в конфигурационном файле качестве минимизаторов по умолчанию:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="webMarkupMin">
<section name="core"
type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
…
</sectionGroup>
…
</configSections>
…
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<core>
…
<css defaultMinifier="KristensenCssMinifier">
<minifiers>
<add name="NullCssMinifier"
displayName="Null CSS Minifier"
type="WebMarkupMin.Core.Minifiers.NullCssMinifier, WebMarkupMin.Core" />
<add name="KristensenCssMinifier"
displayName="Mads Kristensen's CSS minifier"
type="WebMarkupMin.Core.Minifiers.KristensenCssMinifier, WebMarkupMin.Core" />
</minifiers>
</css>
<js defaultMinifier="CrockfordJsMinifier">
<minifiers>
<add name="NullJsMinifier"
displayName="Null JS Minifier"
type="WebMarkupMin.Core.Minifiers.NullJsMinifier, WebMarkupMin.Core" />
<add name="CrockfordJsMinifier"
displayName="Douglas Crockford's JS Minifier"
type="WebMarkupMin.Core.Minifiers.CrockfordJsMinifier, WebMarkupMin.Core" />
</minifiers>
</js>
…
</core>
…
</webMarkupMin>
…
</configuration>
Если CSS- и JS-минимизаторы зарегистрированы в конфигурационном файле, то их экземпляры можно создать следующим образом:
ICssMinifier cssMinifier =
WebMarkupMinContext.Current.Code.CreateCssMinifierInstance("KristensenCssMinifier");
IJsMinifier jsMinifier =
WebMarkupMinContext.Current.Code.CreateJsMinifierInstance("CrockfordJsMinifier");
Если вы просто хотите создать экземпляры CSS- и JS-минимизаторов, которые зарегистрированы как минимизаторы по умолчанию, то это можно сделать следующим образом:
ICssMinifier cssMinifier =
WebMarkupMinContext.Current.Code.CreateDefaultCssMinifierInstance();
IJsMinifier jsMinifier =
WebMarkupMinContext.Current.Code.CreateDefaultJsMinifierInstance();
Помимо ручной обработки ошибок и предупреждений в WebMarkupMin также предусмотрена возможность подключения логгеров, с помощью которых вы можете централизованно записывать ошибки и предупреждения в собственные журналы. Логгером может быть любой класс, реализующий интерфейс ILogger
или наследующий базовый класс LoggerBase
из пространства имен WebMarkupMin.Core.Loggers
.
Ядро содержит два класса, которые реализуют интерфейс ILogger
:
Errors
и Warnings
класса MarkupMinificationResult
.ThrowExceptionLogger
генерирует исключение типа MarkupMinificationException
.Экземпляр логгера можно передать в минимизатор разметки через его конструктор:
var htmlMinifier = new HtmlMinifier(logger: new ThrowExceptionLogger());
Если минимизатор разметки создается на основе параметров конфигурационного файла, то логгер можно передать в него путем регистрации в конфигурационном файле в качестве логгера по умолчанию:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="webMarkupMin">
<section name="core"
type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
…
</sectionGroup>
…
</configSections>
…
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<core>
…
<logging defaultLogger="ThrowExceptionLogger">
<loggers>
<add name="NullLogger"
displayName="Null Logger"
type="WebMarkupMin.Core.Loggers.NullLogger, WebMarkupMin.Core" />
<add name="ThrowExceptionLogger" displayName="Throw exception logger"
type="WebMarkupMin.Core.Loggers.ThrowExceptionLogger, WebMarkupMin.Core" />
</loggers>
</logging>
</core>
…
</webMarkupMin>
…
</configuration>
Если логгер зарегистрирован в конфигурационном файле, то его экземпляр можно создать следующим образом:
ILogger logger = WebMarkupMinContext.Current.CreateLoggerInstance("ThrowExceptionLogger");
Соответственно для создания логгера, зарегистрированного как логгер по умолчанию, можно использовать следующий код:
ILogger logger = WebMarkupMinContext.Current.CreateDefaultLoggerInstance();
Также предусмотрена возможность использования единственного экземпляра логгера для всего приложения:
ILogger logger = WebMarkupMinContext.Current.GetLoggerInstance("ThrowExceptionLogger");
и
ILogger logger = WebMarkupMinContext.Current.GetDefaultLoggerInstance();
Встроенные минимизаторы CSS- и JS-кода производят лишь простые оптимизации и не могут обеспечить высокую степень сжатия. Для решения данной проблемы были созданы дополнительные модули, содержащие адаптеры для популярных в .NET сообществе минимизаторов: Microsoft Ajax Minifier [17] и YUI Compressor for .Net [18].
Модуль WebMarkupMin.MsAjax содержит два адаптера-минимизатора: MsAjaxCssMinifier
и MsAjaxJsMinifier
. Аналогичным образом организован и модуль WebMarkupMin.Yui: YuiCssMinifier
и YuiJsMinifier
.
Адаптеры-минимизаторы можно передать в минимизатор разметки, с помощью тех же самых механизмов, что и встроенные минимизаторы.
Кроме того, настройки вышеперечисленных внешних минимизаторов можно менять в секциях webMarkupMin/msAjax
и webMarkupMin/yui
конфигурационного файла (тем, кто пользуется Bundle Transformer, это покажется знакомым).
Модуль WebMarkupMin.Web работает на уровне ядра ASP.NET, и поэтому может использоваться в любом из существующих ASP.NET-фреймворков: Web Forms, MVC и Web Pages.
WebMarkupMin.Web содержит классы HTTP-модулей, которые позволяют минимизировать и сжимать код, который генерируется средствами ASP.NET:
text/html
средствами HTML Minifier.text/html
или application/xhtml+xml
средствами XHTML Minifier.application/xhtml+xml
) средствами XML Minifier.
Перечисленные выше HTTP-модули могут обрабатывать только GET-запросы и ответы с кодом состояния равным 200
. Следует также отметить, что HtmlMinificationModule
и XhtmlMinificationModule
не могут использоваться вместе.
Рассмотрим пример регистрации HTTP-модулей в файле Web.config
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
…
<system.webServer>
<modules>
<add name="HtmlMinificationModule"
type="WebMarkupMin.Web.HttpModules.HtmlMinificationModule, WebMarkupMin.Web" />
<add name="CompressionModule"
type="WebMarkupMin.Web.HttpModules.CompressionModule, WebMarkupMin.Web" />
…
</modules>
…
</system.webServer>
…
</configuration>
Кроме того, поведением этих HTTP-модулей можно управлять с помощью конфигурационной секции webMarkupMin/webExtensions
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="webMarkupMin">
<section name="core"
type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
<section name="webExtensions"
type="WebMarkupMin.Web.Configuration.WebExtensionsConfiguration, WebMarkupMin.Web" />
…
</sectionGroup>
…
</configSections>
…
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
…
<webExtensions enableMinification="true"
disableMinificationInDebugMode="true"
enableCompression="true" disableCompressionInDebugMode="true"
maxResponseSize="100000" />
…
</webMarkupMin>
…
</configuration>
Подробно рассмотрим все свойства конфигурационной секции webExtensions
:
Табл. 2 Свойства конфигурационной секции webExtensions
Свойство | Тип данных | Значение по умолчанию | Описание |
---|---|---|---|
enableMinification |
Булевский | true |
Включает минимизацию разметки. |
disableMinificationInDebugMode |
Булевский | true |
Отключаем минимизацию разметки в режиме отладки. |
enableCompression |
Булевский | true |
Включает HTTP-сжатие текстового содержимого. |
disableCompressionInDebugMode |
Булевский | true |
Отключает HTTP-сжатие текстового содержимого в режиме отладки. |
maxResponseSize |
Целое число | 100 000 |
Максимальный размер HTTP-ответа (в байтах), при превышении которого отключается минимизация разметки. |
Данные настройки, также используются другими модулями WebMarkupMin: WebMarkupMin.Mvc и WebMarkupMin.WebForms.
Несмотря на то, что описанные выше HTTP-модули можно использовать совместно с любым ASP.NET-фреймворком, для MVC и Web Forms все же рекомендуется использовать более специализированные решения, потому что HTTP-модули не поддерживают кэширование. Использование HTTP-модулей подойдет для небольших сайтов, написанных на ASP.NET Web Pages.
Модуль WebMarkupMin.Mvc ориентирован на использование в веб-приложениях, написанных на ASP.NET MVC версий 3 и 4.
WebMarkupMin.Mvc содержит 4 фильтра:
text/html
, то генерируется исключение типа InvalidContentTypeException
.text/html
или application/xhtml+xml
, то генерируется исключение типа InvalidContentTypeException
.InvalidContentTypeException
.Приведу простой пример использования фильтров:
namespace WebMarkupMin.Example.Mvc.Controllers
{
using System.Web.Mvc;
using Infrastructure.ActionResults;
using WebMarkupMin.Mvc.ActionFilters;
public class HomeController : Controller
{
[CompressContent]
[MinifyHtml]
[OutputCache(CacheProfile = "CacheCompressedContent5Minutes")]
public ActionResult Index()
{
…
}
…
}
}
Поскольку минимизация разметки и HTTP-сжатие требуют некоторого времени и ресурсов сервера, то мы кэшируем результат их работы с помощью фильтра OutputCacheAttribute
.
Модуль WebMarkupMin.WebForms ориентирован на использование в веб-приложениях, написанных на ASP.NET Web Forms версий 4.0 и 4.5.
WebMarkupMin.WebForms содержит 3 класса страниц Web Forms:
Для того чтобы добавить поддержку HTML-минимизации и HTTP-сжатия в страницу Web Forms, нужно просто ее наследовать от класса MinifiedAndCompressedHtmlPage
:
namespace WebMarkupMin.Example.WebForms
{
using System;
using WebMarkupMin.WebForms.Pages;
public partial class Contact : MinifiedAndCompressedHtmlPage
{
…
}
}
Если нужно отключить минимизацию разметки и HTTP-сжатие во время возврата формы, то можно воспользоваться свойствами страницы EnableMinification
и EnableCompression
:
private void Page_PreLoad(object sender, EventArgs e)
{
if (IsPostBack)
{
EnableMinification = false;
EnableCompression = false;
}
}
Результат минимизации разметки и HTTP-сжатия рекомендуется кэшировать с помощью директивы OutputCache
:
<%@ Page Title="Contact" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Contact.aspx.cs" Inherits="WebMarkupMin.Example.WebForms.Contact" %>
<%@ OutputCache CacheProfile="CacheCompressedContent5Minutes" VaryByParam="*" %>
…
Также в модуле WebMarkupMin.WebForms есть аналогичные классы для мастер-страниц: CompressedMasterPage
, MinifiedAndCompressedHtmlMasterPage
и MinifiedAndCompressedXhtmlMasterPage
.
Для добавления поддержки HTML-минимизации и HTTP-сжатия в мастер-страницу, ее нужно наследовать от класса MinifiedAndCompressedHtmlMasterPage
:
namespace WebMarkupMin.Example.WebForms
{
using System;
using System.Web.UI;
using WebMarkupMin.WebForms.MasterPages;
public partial class Site : MinifiedAndCompressedHtmlMasterPage
{
…
}
}
Следует также отметить, что классы страниц и мастер-страниц не могут использоваться совместно.
При минимизации разметки средствами HTML-минимизатора из WebMarkupMin можно сократить размер кода на 25-40%. Некоторые специалисты по клиентской оптимизации могут сказать, что при использовании HTTP-сжатия можно сэкономить в несколько раз больше. В чем-то они окажутся правы, но ничто не мешает использовать HTML-минимизацию и HTTP-сжатие совместно. Следует также помнить, что у минимизации кода по сравнению со сжатием, есть одно существенное преимущество: минимизированный код сразу обрабатывается браузером (при использовании HTTP-сжатия требуется этап распаковки).
Чтобы продемонстрировать возможности HTML-минимизатора возьмем в качестве примера главные страницы четырех популярных в Рунете сайтов, написанных на ASP.NET, и минимизируем их. Мы будем использовать HTML-минимизатор с параметрами минимизации по умолчанию, в качестве CSS-минимизатора установим YuiCssMinifier
, а в качестве JS-минимизатора — MsAjaxJsMinifier
.
Табл. 3. Результаты HTML-минимизации без HTTP-сжатия
Название сайта | Адрес | Размер до минимизации* | Размер после минимизации* | Экономия |
---|---|---|---|---|
Афиша | www.afisha.ru [19] | 162,28 КБ | 110,64 КБ | 31,82% |
МТС | www.mts.ru [20] | 80,56 КБ | 48,50 КБ | 39,80% |
OZON | www.ozon.ru [21] | 107,32 КБ | 62,21 КБ | 42,03% |
Workle | www.workle.ru [22] | 115,26 КБ | 72,94 КБ | 36,72% |
Табл. 4. Результаты HTML-минимизации с включенным HTTP-сжатием (в данном примере использовалось GZIP-сжатие)
Название сайта | Адрес | Размер до минимизации* | Размер после минимизации* | Экономия |
---|---|---|---|---|
Афиша | www.afisha.ru [19] | 30,01 КБ | 25,47 КБ | 15,14% |
МТС | www.mts.ru [20] | 19,08 КБ | 14,15 КБ | 25,86% |
OZON | www.ozon.ru [21] | 16,58 КБ | 14,23 КБ | 14,22% |
Workle | www.workle.ru [22] | 19,06 КБ | 17,31 КБ | 9,15% |
* — при расчетах предполагалось, что 1 Кбайт = 1 024 байт
Из табл. 3 видно, что при использовании минимизации без HTTP-сжатия можно сократить размер HTML-документа в среднем на 37,59%, а это очень хороший показатель.
При использовании минимизации вместе с HTTP-сжатием (табл. 4) вклад минимизации в снижение размера страницы уже не такой существенный. Но в тоже время для Афиши и МТС мы получили очень неплохой результат в абсолютном выражении: выигрыш от минимизации 4,54 и 4,93 Кбайт соответственно. Если учитывать, что эти 2 сайта имеют очень высокую посещаемость, то экономия исходящего трафика может оказаться существенной.
Вы можете самостоятельно провести аналогичные измерения для своего сайта, используя онлайн-версию HTML-минимизатора на сайте WebMarkupMin Online [23].
Рис. 2. Онлайн-версия HTML-минимизатора на сайте WebMarkupMin Online
Автор: Taritsyn
Источник [26]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/asp-net-mvc/33128
Ссылки в тексте:
[1] «Сжатие JS- и CSS-файлов»: http://taritsyn.wordpress.com/2012/01/26/klientskaja-optimizacija-v-asp-net-mvc-3-szhatie-js-i-css-fajlov/
[2] «Менеджеры ресурсов»: http://taritsyn.wordpress.com/2012/02/17/klientskaja-optimizacija-v-asp-net-mvc-3-menedzhery-resursov/
[3] Bundle Transformer: http://bundletransformer.codeplex.com/
[4] «Паранойя оптимизатора»: http://web.ggpi.org/docs/artlebedev/kovodstvo/paragraphs/17.html
[5] HTML Shrinker: http://thepluginsite.com/products/htmlshrinker/index.htm
[6] Absolute HTML Compressor: http://www.alentum.com/ahc/
[7] HTML Code Cleaner: http://www.htmlcodecleaner.com-http.com/
[8] HTMLOpt: http://www.alonewolfsoft.ru/html_optimizer.htm
[9] руководстве по оформлению HTML/CSS кода от Google: http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml
[10] «Optimizing HTML»: http://perfectionkills.com/optimizing-html/
[11] HtmlCompressor: http://code.google.com/p/htmlcompressor/
[12] Experimental HTML Minifier: http://github.com/kangax/html-minifier
[13] CodePlex: http://webmarkupmin.codeplex.com/
[14] NuGet: http://nuget.org/packages?q=webmarkupmin
[15] Efficient stylesheet minifier: http://madskristensen.net/post/Efficient-stylesheet-minification-in-C.aspx
[16] JSMin: http://www.crockford.com/javascript/jsmin.html
[17] Microsoft Ajax Minifier: http://ajaxmin.codeplex.com/
[18] YUI Compressor for .Net: http://yuicompressor.codeplex.com/
[19] www.afisha.ru: http://www.afisha.ru/
[20] www.mts.ru: http://www.mts.ru/
[21] www.ozon.ru: https://www.ozon.ru/
[22] www.workle.ru: http://www.workle.ru/
[23] WebMarkupMin Online: http://webmarkupmin.apphb.com/
[24] Image: http://taritsyn.files.wordpress.com/2013/04/webmarkupmin-online.png
[25] перевод: http://habrahabr.ru/post/143452/
[26] Источник: http://habrahabr.ru/post/178081/
Нажмите здесь для печати.