BundleTransformer.Less вводит переменные в зависимости от контекста / запроса
Мы хотели бы использовать механизм связывания System.Web.Optimization
в сочетании с трансформатором Less.
Проблема в том, что одно и то же приложение / сервер обслуживает страницы для разных фирменных сайтов. Таким образом, в зависимости от 'SiteContext' используются одни и те же файлы.less, но переменные.less должны использовать разные значения. Таким образом, мы хотим (повторно) использовать те же файлы меньше, но с разными переменными в зависимости от контекста запроса.
Я попробовал пару разных теорий:
Во всех 3 случаях я устанавливаю разные пакеты в зависимости от SiteContext.
1 внедрить директиву @import с тематическими переменными, используя пользовательский VirtualPathProvider, который перехватывает файл variables.less.
Так что я:
- файл стиля, например: header.less (импортирует файл переменных)
- файл переменных: variables.less
- файл тематических переменных: variable-theme.less (внедряется в variables.less через VirtualPathProvider)
Это не работает, потому что кеш BundleTransformer видит это как тот же файл и не знает о SiteContext. Ключ кеша основан на URL-адресе IAsset
и мы не можем влиять на это поведение.
2 Замените импорт variables.less на variable-themed.less пользовательским преобразователем, который запускается перед преобразователем Less.
Опять не повезло, те же проблемы с кешированием.
И как побочный эффект, дополнительный трансформатор не был вызван в отладке, потому что активы не связаны, а вызываются индивидуально LessAssetHandler
, Это можно решить, написав свой собственный AssetHandler, который вызывает все необходимые преобразователи.
3 создать тематические имена активов, которые разрешаются с помощью пользовательского VirtualPathProvider, например. Добавьте header-themeX.less к комплекту, этот файл не существует, но вы разрешаете этот файл в header.less и используете метод 2 для установки правильного импорта файла переменных. (замените импорт переменных.less на тематическую версию).
Еще раз не повезло. Я думаю, что это может решить проблему кэширования, если бы не Bundle.Include(string virtualPath)
это делает File.Exists(path)
внутренне. Это не проходит через CustomVirtualPathProvider
,
Я ищу глубоко, чтобы решить это? Все идеи приветствуются, я могу представить, что это станет проблемой для все большего числа людей, поскольку System.Web.Optimization
библиотека становится все популярнее...
Имейте в виду, что:
- у нас много файлов.less / css
- у нас будет около 5 тем
- нам нравится, чтобы все работало в визуальной студии (поэтому в header.less есть ссылка на variables.less)
Спасибо за любые отзывы.
1 ответ
Майкл!
Вы используете Microsoft ASP.NET Web Optimization Framework и Bundle Transformer в мультитенантной среде, поэтому вам необходимо заменить некоторые компоненты System.Web.Optimization и создать собственные версии отладочных HTTP-обработчиков (см. "Проблема: LESS". импорт файлов добавлен в коллекцию BundleResponse.Files " обсуждение). Насколько я знаю, Мурат Чакир решает все эти проблемы в проекте SmartStore.NET.
В Bundle Transformer есть 2 способа ввода LESS-переменных:
Смотреть свойства
GlobalVariables
а такжеModifyVariables
LESS-переводчик:using System.Collections.Generic; using System.Web.Optimization; using BundleTransformer.Core.Builders; using BundleTransformer.Core.Orderers; using BundleTransformer.Core.Transformers; using BundleTransformer.Core.Translators; using BundleTransformer.Less.Translators; public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { var nullBuilder = new NullBuilder(); var nullOrderer = new NullOrderer(); var lessTranslator = new LessTranslator { GlobalVariables = "my-variable='Hurrah!'", ModifyVariables = "font-family-base='Comic Sans MS';body-bg=lime;font-size-h1=50px" }; var cssTransformer = new CssTransformer(new List<ITranslator>{ lessTranslator }); var commonStylesBundle = new Bundle("~/Bundles/BootstrapStyles"); commonStylesBundle.Include( "~/Content/less/bootstrap-3.1.1/bootstrap.less"); commonStylesBundle.Builder = nullBuilder; commonStylesBundle.Transforms.Add(cssTransformer); commonStylesBundle.Orderer = nullOrderer; bundles.Add(commonStylesBundle); } }
Создайте пользовательское преобразование элемента:
using System.Text; using System.Web.Optimization; public sealed class InjectContentItemTransform : IItemTransform { private readonly string _beforeContent; private readonly string _afterContent; public InjectContentItemTransform(string beforeContent, string afterContent) { _beforeContent = beforeContent ?? string.Empty; _afterContent = afterContent ?? string.Empty; } public string Process(string includedVirtualPath, string input) { if (_beforeContent.Length == 0 && _afterContent.Length == 0) { return input; } var contentBuilder = new StringBuilder(); if (_beforeContent.Length > 0) { contentBuilder.AppendLine(_beforeContent); } contentBuilder.AppendLine(input); if (_afterContent.Length > 0) { contentBuilder.AppendLine(_afterContent); } return contentBuilder.ToString(); } }
И зарегистрируйте это преобразование следующим образом:
using System.Web.Optimization;
using BundleTransformer.Core.Orderers;
using BundleTransformer.Core.Bundles;
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
var nullOrderer = new NullOrderer();
const string beforeLessCodeToInject = @"@my-variable: 'Hurrah!';";
const string afterLessCodeToInject = @"@font-family-base: 'Comic Sans MS';
@body-bg: lime;
@font-size-h1: 50px;";
var commonStylesBundle = new CustomStyleBundle("~/Bundles/BootstrapStyles");
commonStylesBundle.Include(
"~/Content/less/bootstrap-3.1.1/bootstrap.less",
new InjectContentItemTransform(beforeLessCodeToInject, afterLessCodeToInject));
commonStylesBundle.Orderer = nullOrderer;
bundles.Add(commonStylesBundle);
}
}
Оба способа имеют недостаток: внедрение LESS-переменных не работает в режиме отладки.