Не даем бандлам испортить вам жизнь

в 14:06, , рубрики: .net, ASP

Не даем бандлам испортить вам жизнь
Недавно столкнулся с проблемой конфликта бандлов в MVC проекте, случалось так, что некоторые скрипты оказывались по нескольку раз подключенными в разных бандлах. Вычленение какого-то лишнего скрипта из одного из них может привести к серьезной головной боли, ведь один и то же бандл может использоваться на разных лейаутах.

Я видел разные способы группировки скриптов, но, честно говоря, ни один из них мне до конца не нравился. Как все-таки группировать скрипты так, чтобы было сложнее всего в них запутаться и не приходилось бы заморачиваться по поводу конфликтов разных бандлов на одной странице? Для себя я придумал подход, который, на мой взгляд, упросит жизнь. Очень буду рад здоровой критике и полезным советам.

Начнем с того, что попробуем проанализировать парочку подходов для группировки скриптов:
Первый подход — объединение в группы по общему назначению скриптов.

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
    "~/Scripts/jquery-{version}.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
    "~/Scripts/jquery-ui-{version}.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
    "~/Scripts/jquery.unobtrusive*",
    "~/Scripts/jquery.validate*"));

Достаточно просто и проблем быть не должно, но этого подхода не достаточно. Кастомные скрипты тоже как-то нужно сгруппировать. Здесь и возникает второй подход — объединение скриптов в какой-то базовый бандл.

bundles.Add(new ScriptBundle("~/Scripts/base").Include(
    "~/Scripts/placeholder.js",
    "~/Scripts/modernizr-*",
    "~/Scripts/my-custom-script-1",
    "~/Scripts/my-custom-script-2));

И тут же возникает вопрос что сюда включать. Jquery вроде базовый скрипт, но для него у нас уже есть отдельный бандл. Такая же история может случиться и с любым другим скриптом, который один из разработчиков в большой команде посчитает, что его нужно туда включить. Таким образом чем больше мнений — тем больше неожиданных проблем с группировкой скриптов.

Я для себя выбрал следующий путь:
1. На каждый лэйаут — 1 бандл.
Называю бандл таким же именем, как и сам лэйаут и решаю головную боль с тем, что подключать, куда подключать и сколько подключать.

2. Бандлы подключаются только на лэйаутах.
В итоге: сколько лэйаутов — столько и одноименных бандлов.

Если здесь у вас возникла буря негодований, то попридержите их до конца пути, когда сложится целостная картина.

3. Вводим понятие групп, которое будет являться просто массивом строк.
В группу объединяем все необходимые скрипты для какого-то конкретного функционала. Вот пример группы скриптов для рендеринга отчетов с графиками на svg холстах:

var reportScriptGroup = new[]
{
    "~/Scripts/jquery-{version}.js",
    "~/Scripts/raphael.js",
    "~/Scripts/Custom/charts.js",
    "~/Scripts/Custom/report.js"
};

Предположим, что в этом же лэйауте вам необходима клиентская валидация, добавляем группу для валидации:

var validationScriptGroup = new[]
{
    "~/Scripts/jquery-{version}.js",
    "~/Scripts/jquery.validate.js",
    "~/Scripts/jquery.validate.unobtrusive.js",
    "~/Scripts/Custom/jquery.custom.validate.js"
};

Обратите внимание на наличие jquery-{version}.js в обоих группах, но это нам не мешает добавить обе группы в один и тот же бандл. Он сам позаботится о том, чтобы сделать дистинкт.

bundles.Add(new ScriptBundle("~/Scripts/_DashboardLayout")
        .Include(baseScriptGroup)
        .Include(validationScriptGroup)
        .Include(reportScriptGroup)
    )
);

4. Мне также понадобилось исключить скрипт из группы, чтобы не создавать новую.
Например, скрипт, который показывает страницу постепенно ее разблюривая. Он находится в группе baseScriptGroup. Мне он совершенно не нужен на лэйауте для подготовки всякого добра к печати или конвертации в pdf и т.п.

Напишем нехитрый метод для исключения скрипта из группы:

private static string[] Exclude(this IEnumerable<string> input, params string[] items)
{
    var output = input;
    foreach (var item in items)
    {
        output = output.Where(x => x != item).ToArray();
    }

    return output.ToArray();
}

А бандл для него будет выглядеть вот так:

bundles.Add(new ScriptBundle("~/Scripts/_PrintLayout")
        .Include(baseScriptGroup.Exclude("~/Scripts/Custom/fading.js"))
        .Include(reportScriptGroup)
    )
);

Вот и все. Таким образом можно просто объединять группы в бандл. Захотелось подключить графики — добавил в бандл группу с графиками. Захотел валидацию — добавь и ее.

Автор: ne4ta

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js