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