К слову сказать, объединение (связывание) и минификация – это общий процесс, применимый к сайтам любых типов, независимо от того, на каком языке программирования они написаны. Изучив этот вид оптимизации, Вы сможете применять его, используя ваши рабочие среду разработки и сопутствующие инструменты.
Чтобы комплексно изучить данный вопрос, мы рассмотрим следующие моменты:
- Посмотрим на обычное веб-приложение и отметим проблемы, которые можно решить, применив объединение и минификацию файлов;
- Определим понятие, что такое объединение и минификация, смысл их использования;
- Оптимизируем веб-приложение, применив данный подход;
- Проанализируем результат и сравним с тем, что было в начале;
- Добавим кэширование для статичных файлов;
- Подготовим веб-приложение к публикации, сделав соответствующие настройки.
Инструменты и технологии, которые мы будем использовать в данном примере:
- Visual Studio (2015, 2017, 2019)
- Расширение «Bundler & Minifier» для Visual Studio (ссылка на официальную страницу)
- Веб-приложение типа ASP.NET Core MVC
Чтобы быстрее разобраться в сути вопроса, давайте сразу перейдем к практике и посмотрим на существующую проблему. Для этого в Visual Studio создадим новое веб-приложение типа ASP.NET Core MVC. В качестве шаблона будем использовать стандартный пред подготовленный (Model-View-Controller), чтобы можно было сразу запустить приложение в работу.
Если посмотреть какие файлы были созданы в шаблоне, то мы увидим, что были добавлены файлы стилей CSS, а также файлы скриптов JavaScript, включая такие популярные проекты как Bootstrap и jQuery. При необходимости мы можем добавить несколько собственноручно созданных файлов для наглядности.
Подключим все эти файлы в нашем приложении в мастер-странице (лишний код скрыт):
<!DOCTYPE html>
<html>
<head>
...
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
<link rel="stylesheet" href="~/css/style.css" />
...
</head>
<body>
...
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js"></script>
<script src="~/js/custom.js"></script>
...
</body>
</html>
После этого запустим веб-приложение и проанализируем сетевой трафик:
Мы видим, что к серверу было отправлено девять запросов, всего передано 730 КБ данных, время на полную загрузку страницы составило 590 мс. Также представлен список всех статичных переданных файлов.То есть на каждый файл отдельный запрос к серверу.
Как мы можем оптимизировать наше веб-приложение в данный момент? Мы можем уменьшить объем передаваемых данных по сети, а также мы можем сократить количество запросов к серверу, чем меньше, тем лучше.
В этом нам поможет использование объединения и минификации статичных файлов. Другими словами, мы можем сократить количество файлов и сжать их содержимое.
Объединение и минификация файлов (Bundling and Minification)
В нашем веб-приложении мы с легкостью можем применить данный вид оптимизации. Объединим все файлы стилей CSS в один, объединим все файлы скриптов JS в один, а также сократим содержимое этих файлов, тем самым они будут меньше весить.
Для начала нам нужно настроить Visual Studio, а именно установить расширение «Bundler & Minifier».
Установка будет поставлена в очередь и потребуется перезагрузка среды Visual Studio.
После того, как дополнение установлено и готово к работе, мы можем начать процесс объединения и минификации файлов.
Начнем с CSS-файлов. Для этого в Solution Explorer выделяем все нужные файлы. После этого в контекстном меню выбираем пункт Bundle and Minify Files. Будет предложено дать название новому файлу и выбрать место для его сохранения.
В этом примере я обозвал файл bundleCss.css и сохранил его в новой папке content.
После первого применения минификации в корне проекта появится конфигурационный файл bundleconfig.json, в котором можно более гибко настроить правила связывания и минификации.
Подобным образом поступаем и с файлами скриптов JS - bootstrap.bundle.js, custom.js, site.js.
Однако библиотеку jquery.js включать в бандл не надо. Этот скрипт должен подключаться отдельным файлом в отдельном запросе для правильной работы и обязательно перед всеми остальными скриптами. Вместо этого мы просто скопируем его из папки \lib\jquery\dist\ в новую папку content.
В результате структура файлов будет выглядеть таким образом:
Обратите внимание, чтобы были созданы минифицированные версии файлов с расширением .min. Именно это версии файлов мы будем подключать в мастер-странице.
Нам осталось подключить в мастер-странице новые минифицированные бандлы:
<!DOCTYPE html>
<html>
<head>
...
<link rel="stylesheet" href="~/content/bundleCss.min.css" />
...
</head>
<body>
...
<script src="~/content/jquery.min.js"></script>
<script src="~/content/bundleJs.min.js"></script>
...
</body>
</html>
После этого перезапустим веб-приложение и вновь проанализируем сетевой трафик:
Количество запросов сократилось с девяти до пяти. Объем переданных данных с 730 КБ до 350 КБ. Время полной загрузки страницы сократилось с 590 мс до 440 мс.
Таким образом, некоторые показатели изменились примерно в два раза. В нашем простом примере это не сильно заметно, однако в реальных больших проектах разница может достигать сотен процентов.
Вот таким образом работает оптимизация веб-приложения путем применения минификации и объединения статичных файлов. Сокращая количество запросов к серверу, мы снижаем нагрузку на сервер. Сокращая объем файлов, мы уменьшаем сетевой трафик, передаваемый клиенту. Все это в целом повышает быстродействие нашего веб-приложения, и как следствие, удобство для конечных пользователей.
Кэширование статичных файлов
Обсуждая тему оптимизации работы со статичными файлами, также следует обратить внимание на такой важный аспект, как кэширование. Применимо нашей темы можно дать такое определение:
Таким образом, снижается нагрузка на сервер (серверу не приходится обслуживать данный запрос) и повышается быстродействие приложения (кэш ближе к клиенту и файл передается быстрее).
Давайте в нашем веб-приложении укажем, какие файлы кэшировать и как управлять кэшированием этих файлов.
Во-первых, добавим в коде специальный атрибут ко всем тег-хелперам, которые подключают статичные файлы:
<link rel="stylesheet" href="/content/bundleCss.min.css" asp-append-version="true" />
asp-append-version="true" – данный атрибут добавляет к имени файла подстроку, содержащую контрольную сумму, которая отражает «версию» файла. В результате конечный HTML-код будет выглядеть следующим образом:
<link rel="stylesheet" href="/content/bundleCss.min.css?v=dkymHvTKJi-S47EBy_hrOtFIrpqvibgzaYqvwQ5DP-g" />
Данная версия файла будет использоваться до тех пор, пока Вы не измените его содержимое. При любом изменении контрольная сумма файла будет пересчитана. Для конечного клиента (браузера) это означает, что он будет делать запрос к новому URL на сервере. То есть такой запрос не будет перехвачен кэшем, и новая версия файла будет загружена в кэш.
Во-вторых, добавим специальный HTTP-заголовок (HTTP Header) Cache-Control в ответах сервера, который будет использоваться для задания инструкций как кэшировать файлы.
Для этого в файле Startup.cs в методе Configure() изменим настройку, которая позволяет обслуживать статичные файлы в приложении, следующим образом:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//... остальной код ...
var fileOptions = new StaticFileOptions
{
OnPrepareResponse = (context) => context.Context.Response.Headers[HeaderNames.CacheControl] = "public, max-age=604800"
};
app.UseStaticFiles(fileOptions);
//... остальной код ...
}
Значение заголовка "public, max-age=604800" означает, что файлы разрешено кэшировать на любом уровне, будь то конечный браузер пользователя, или публичный прокси-сервер. При этом файл считается актуальным на протяжении семи дней (604800 секунд).
Для нашего примера такая простая политика кэширования подходит. Однако в реальных проектах к этому вопросу стоит подходить очень внимательно. Более подробную информацию по этой теме можно найти в интернете, например, в блоге Google.
Настройка публикации проекта
Последнее, что осталось настроить в нашем веб-приложении – это правила публикации проекта. Мы объединили и минифицировали нужные нам статичные файлы. Теперь именно они используются и подключаются в коде приложения.
Оригинальные версии файлов теперь служат как источник данных и напрямую не используются в коде. Соответственно, и публиковать их в продакшн не имеет смысла. Давайте исключим эти файлы из публикации.
Открываем файл проекта на редактирование и добавляем следующие директивы:
<ItemGroup>
<Content Update="wwwroot\**" CopyToPublishDirectory="Never" />
<Content Update="wwwroot\content\**" CopyToPublishDirectory="Always" />
</ItemGroup>
В этом коде мы запрещаем к публикации все внутреннее содержимое папки wwwroot, сделав исключение для папки content и всего ее содержимого.