Pull to refresh

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

Reading time 3 min
Views 8.9K

Недавно столкнулся с проблемой конфликта бандлов в 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 и т.п.

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

EDITED: по замечанию пользователя lair можно воспользоваться методом Except

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)
    )
);


Вот и все. Таким образом можно просто объединять группы в бандл. Захотелось подключить графики — добавил в бандл группу с графиками. Захотел валидацию — добавь и ее.
Only registered users can participate in poll. Log in, please.
Считаете ли вы такой подход полезным?
12.94% Да, пользуюсь чем-то подобным. 11
27.06% Да, стоит попробовать. 23
14.12% Нет, мне он не нравится. 12
28.24% Нет, у меня не возникает таких проблем. 24
27.06% Что такое бандл? 23
85 users voted. 38 users abstained.
Tags:
Hubs:
+2
Comments 12
Comments Comments 12

Articles