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-переменных:

  1. Смотреть свойства 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);
        }
    }
    
  2. Создайте пользовательское преобразование элемента:

    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-переменных не работает в режиме отладки.

Другие вопросы по тегам