Главная > .NET, JavaScript > Bundle Transformer: Летние обновления

Bundle Transformer: Летние обновления

Логотип Bundle Transformer на сельскохозяйственном поле

Начиная с сентября прошлого года, когда библиотека MSIE JavaScript Engine for .NET была заменена библиотекой JavaScript Engine Switcher и был создан модуль BundleTransformer.CleanCss, в Bundle Transformer практически не было каких-либо революционных изменений. Изменения были в основном эволюционными: добавлялась поддержка новых версий минимизаторов и трансляторов (самая рутинная и сложная часть работы над проектом), исправлялись мелкие ошибки и шла работа над увеличением производительности.

Но этим летом все изменилось: с конца мая по июль от пользователей Bundle Transformer было получено огромное количество рекомендаций по улучшению проекта. Большая часть из них была реализована в версии 1.9.0 и последующих летних обновлениях. В данной статье мы рассмотрим наиболее значимые из них:

Классы StyleTransformer и ScriptTransformer

Изначально для классов CssTransformer и JsTransformer были выбраны не совсем удачные имена, потому что выбор имен производился по аналогии с классами CssMinify и JsMinify из System.Web.Optimization. Когда в System.Web.Optimization появились классы StyleBundle и ScriptBundle, то стало понятно, что эти названия никуда не годятся.

Я долго откладывал переименование этих классов на потом, но при работе над версией 1.9.0 я решил их все-таки переименовать. Теперь они называются StyleTransformer и ScriptTransformer. Старые классы CssTransformer и JsTransformer по-прежнему доступны в ядре (реализованы как обертки над новыми классами), но они считаются устаревшими (помечены атрибутом Obsolete) и будут удалены в версии 2.0.0.

Постпроцессоры

В конце мая мне пришел pull request «Support for Autoprefixer» от Вегарда Ларсена (сотрудника норвежской компании Digital Creations). При просмотре кода сразу стало понятно, что текущая архитектура Bundle Transformer не подходит для реализации таких модулей. Вегард реализовал функционал этого модуля в виде транслятора стилей, который должен был запускаться после всех остальных трансляторов (LESS, Sass и т.д.). Вся эта реализация выглядела как хак, поэтому я принял решение отклонить данный pull request. В итоге Вегард опубликовал в NuGet неофициальную версию модуля — BundleTransformer.Autoprefixer.Unofficial, а я начал работу над новой архитектурой Bundle Transformer.

Требовался новый тип модулей, которые должны были запускаться после трансляторов и перед минимизаторами, причем количество и порядок вызова таких модулей должен определяться разработчиком. В качестве названия для нового типа модулей я решил использовать термин «постпроцессоры», который придумал Андрей Ситник (если вы не знаете, кто такой Андрей Ситник или что такое постпроцессоры, то рекомендую вам прослушать 6-й выпуск подкаста Frontflip).

Постпроцессором в Bundle Transformer может быть любой класс, реализующий интерфейс IPostProcessor или наследующий базовый класс PostProcessorBase из пространства имен BundleTransformer.Core.PostProcessors. Как и другие типы модулей (адаптеров) постпроцессоры должны быть зарегистрированы в файле Web.config. Рассмотрим процесс регистрации на примере CSS-постпроцессоров:

<configuration><bundleTransformer …>
    <core …>
      <css
defaultPostProcessors="UrlRewritingCssPostProcessor,AutoprefixCssPostProcessor" …>
        <postProcessors>
          <add name="UrlRewritingCssPostProcessor"
type="BundleTransformer.Core.PostProcessors.UrlRewritingCssPostProcessor, 
BundleTransformer.Core"
            useInDebugMode="false" />
          <add name="AutoprefixCssPostProcessor"
type="BundleTransformer.Autoprefixer.PostProcessors.AutoprefixCssPostProcessor, 
BundleTransformer.Autoprefixer"
            useInDebugMode="true" />
        </postProcessors>
      </css></core></bundleTransformer></configuration>

В элементе /configuration/bundleTransformer/core/css/postProcessors зарегистрированы два постпроцессора:

  1. UrlRewritingCssPostProcessor. Производит преобразование относительных путей в абсолютные (стандартная возможность Bundle Transformer, реализованная в виде постпроцессора).
  2. AutoprefixCssPostProcessor. Добавляет поддержку Autoprefixer`а в Bundle Transformer.

На первый взгляд, это очень похоже на регистрацию минимизаторов, но есть одно небольшое отличие: если в атрибуте defaultMinifier элемента /configuration/bundleTransformer/core/css мы можем указать только один минимизатор, то в атрибуте defaultPostProcessors мы можем задать любое количество постпроцессоров (даже нулевое). Причем порядок, в котором мы указываем имена постпроцессоров в этом атрибуте, определяет порядок их выполнения. Если атрибут отсутствует, то в качестве постпроцессора по умолчанию используется UrlRewritingCssPostProcessor.

Из кода также видно, что значение атрибута useInDebugMode у постпроцессоров различается: у UrlRewritingCssPostProcessor оно равно false (преобразование относительных путей в абсолютные нужно только в режиме выпуска, когда все файлы объединяются в один), а у AutoprefixCssPostProcessortrue (актуализация вендорных префиксов нужна и в режиме отладки, и в режиме выпуска).

Регистрация JavaScript-постпроцессоров практически ничем не отличается от регистрации CSS-постпроцессоров, за исключением того, что она должна производиться в конфигурационном элементе /configuration/bundleTransformer/core/js.

Усовершенствованные отладочные HTTP-хэндлеры

Как правило, большинство пользователей Bundle Transformer настраивают модули декларативным способом (через Web.config), но в некоторых случаях приходится использовать императивный подход. Например, при работе с 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 styleTransformer = new StyleTransformer(
         new List<ITranslator> { lessTranslator });

      var commonStylesBundle = new Bundle("~/Bundles/BootstrapStyles");
      commonStylesBundle.Include("~/Content/bootstrap/bootstrap.less");
      commonStylesBundle.Builder = nullBuilder;
      commonStylesBundle.Transforms.Add(styleTransformer);
      commonStylesBundle.Orderer = nullOrderer;
      bundles.Add(commonStylesBundle);
   }
}

В приведенном выше коде мы явно создаем экземпляр класса LessTranslator и с помощью свойств GlobalVariables и ModifyVariables производим настройку LESS-переменных. При таком подходе мы можем передавать транслятору значения LESS-переменных, полученные из внешнего источника (например, базы данных).

Существует и второй способ работы с LESS-переменными. Сначала нужно создать пользовательскую трансформацию элемента:

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.Bundles;
using BundleTransformer.Core.Orderers;

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/bootstrap/bootstrap.less",
         new InjectContentItemTransform(beforeLessCodeToInject,
            afterLessCodeToInject));
      commonStylesBundle.Orderer = nullOrderer;
      bundles.Add(commonStylesBundle);
   }
}

К сожалению, приведенные выше примеры кода раньше работали только в режиме выпуска. Это было вызвано тем, что отладочные HTTP-хэндлеры ничего «не знали» о настройках бандлов и просто транслировали код запрашиваемых файлов.

Чтобы решить эту проблему нужно было, в первую очередь, найти способ передать отладочным HTTP-хэндлерам URL бандла, в который входит запрашиваемый файл. После изучения кода сборки System.Web.Optimization.dll с помощью декомпилятора решение было найдено: нужно написать свою собственную версию класса BundleResolver и зарегистрировать его в соответствующем классе. Я не буду вдаваться в детали реализации, а просто покажу, как использовать созданный класс:

using BundleTransformer.Core.Resolvers;

public class BundleConfig
{
   public static void RegisterBundles(BundleCollection bundles)
   {
      BundleResolver.Current = new CustomBundleResolver();}
}

После этого в режиме отладки будут генерироваться ссылки на файлы следующего вида:

<link
   href="/Content/bootstrap/bootstrap.less?
bundleVirtualPath=%7e%2fBundles%2fBootstrapStyles"
   rel="stylesheet">

, где параметр строки запроса bundleVirtualPath содержит URL бандла.

Таким образом, имея в распоряжении URL бандла я добавил в базовый отладочный HTTP-хэндлер возможность применять к запрашиваемому файлу, привязанные к нему пользовательские трансформации элементов и трансформации, заданные на уровне бандла (трансляторы и постпроцессоры).

Кроме того, были созданы два дополнительных HTTP-хэндлера:

  1. CssAssetHandler. Для обработки CSS-файлов.
  2. JsAssetHandler. Для обработки JavaScript-файлов.

Они позволяют применять к статическим файлам пользовательские трансформации элементов и постпроцессоры. Если запрашиваемый статический файл не входит ни в один из бандлов, то эти HTTP-хэндлеры передают запрос экземпляру класса System.Web.StaticFileHandler. В отличие, от отладочных HTTP-хэнлеров, идущих в комплекте с трансляторами, данные HTTP-хэндлеры не регистрируются в файле Web.config автоматически (во время установки NuGet-пакетов), их необходимо регистрировать вручную:

<configuration><system.webServer><handlers><add name="CssAssetHandler" path="*.css" verb="GET" 
        type="BundleTransformer.Core.HttpHandlers.CssAssetHandler,
BundleTransformer.Core" 
        resourceType="File" preCondition="" />
      <add name="JsAssetHandler" path="*.js" verb="GET" 
        type="BundleTransformer.Core.HttpHandlers.JsAssetHandler,
BundleTransformer.Core" 
        resourceType="File" preCondition="" /></handlers></system.webServer></configuration>

Сопоставление расширений файлов и типов ресурсов в файле Web.config

Раньше сопоставление расширений файлов и типов ресурсов было жестко зашито в коде класса Asset. Теперь для этого используются конфигурационные элементы fileExtensions из файла Web.config:

<configuration><bundleTransformer …>
    <core …>
      <css …>
        …
        <fileExtensions>
          <add fileExtension=".css" assetTypeCode="Css" />
          <add fileExtension=".less" assetTypeCode="Less" />
          <add fileExtension=".sass" assetTypeCode="Sass" />
          <add fileExtension=".scss" assetTypeCode="Scss" />
        </fileExtensions>
      </css>
      <js …>
        …
        <fileExtensions>
          <add fileExtension=".js" assetTypeCode="JavaScript" />
          <add fileExtension=".coffee" assetTypeCode="CoffeeScript" />
          <add fileExtension=".litcoffee" assetTypeCode="LiterateCoffeeScript" />
          <add fileExtension=".coffee.md" assetTypeCode="LiterateCoffeeScript" />
          <add fileExtension=".ts" assetTypeCode="TypeScript" />
          <add fileExtension=".mustache" assetTypeCode="Mustache" />
          <add fileExtension=".handlebars" assetTypeCode="Handlebars" />
          <add fileExtension=".hbs" assetTypeCode="Handlebars" />
        </fileExtensions>
      </js></core></bundleTransformer></configuration>

В приведенном выше примере показана ситуация, когда установлены все официальные модули Bundle Transformer (сопоставления для расширений .css и .js добавляются при установке ядра, а остальные при установке соответствующих модулей-трансляторов). Такая архитектура дает нам следующие преимущества:

  1. Не нужно хранить неиспользуемые сопоставления. Как правило, в реальных проектах не нужно устанавливать все виды трансляторов (например, одновременное использование LESS и Sass встречается очень редко), таким образом в проекте будет храниться меньшее количество сопоставлений.
  2. Возможность создания неофициальных модулей-трансляторов. Поскольку теперь нет зависимости от кода ядра, то у пользователей Bundle Transformer появилась возможность создавать собственные модули-трансляторы. Примером такого модуля может служить NuGet-пакет AngularBundle, при установке которого в файл Web.config добавляется следующее сопоставление:
    <configuration><bundleTransformer>
        <core><js><fileExtensions><add fileExtension=".html" assetTypeCode="AngularTemplate" /></fileExtensions>
          </js></core></bundleTransformer></configuration>
  3. Привязка новых расширений файлов к существующим модулям-трансляторам. Например, если мы хотим, чтобы модуль BundleTransformer.Hogan начал обрабатывать файлы с расширением .html, нам нужно просто добавить следующий код в файл Web.config:
    <configuration><bundleTransformer>
        <core><js><fileExtensions><add fileExtension=".html" assetTypeCode="Mustache" /></fileExtensions>
          </js></core></bundleTransformer><system.webServer><handlers><add name="HtmlAssetHandler" path="*.html" verb="GET"
            type="BundleTransformer.Hogan.HttpHandlers.HoganAssetHandler,
    BundleTransformer.Hogan"
            resourceType="File" preCondition="" /></handlers></system.webServer></configuration>

Объединение кода файлов перед минимизацией

Bundle Transformer, в отличии от System.Web.Optimization, обрабатывает каждый файл по отдельности и такой подход дает ряд преимуществ:

  1. Появляется возможность объединять в один бандл разные типы ресурсов (например, CSS-, LESS- и Sass-файлы).
  2. Не производится повторная минимизация предварительно минимизированных файлов (файлы с расширениями .min.css и .min.js), что в большинстве случаев увеличивает скорость минимизации при первоначальном обращении к бандлу.

Но некоторым пользователям Bundle Transformer не нравился данный подход, потому что они хотели в полной мере использовать возможности структурной минимизации, которые предоставляют современные минимизаторы (например, CSSO от компании Яндекс).

Поэтому в новой версии у конфигурационных элементов css и js появился атрибут combineFilesBeforeMinification (значение по умолчанию равно false), который позволяет включить объединение кода файлов перед минимизацией:

<configuration><bundleTransformer>
    <core 
      <csscombineFilesBeforeMinification="true"></css>
      <jscombineFilesBeforeMinification="true"></js></core></bundleTransformer></configuration>

Новые модули

За это время для Bundle Transformer было создано сразу три официальных модуля:

  1. Постпроцессор BundleTransformer.Autoprefixer
  2. Транслятор BundleTransformer.Handlebars
  3. Транслятор BundleTransformer.Hogan

Поскольку все три модуля основаны на коде JavaScript-библиотек, то сразу после установки вам нужно для каждого из них выбрать свой JavaScript-движок (более подробную информацию смотрите в файлах readme.txt соответствующих NuGet-пакетов).

Рассмотрим каждый из них по отдельности:

Bundle Transformer: Autoprefixer

Модуль BundleTransformer.Autoprefixer содержит адаптер-постпроцессор AutoprefixCssPostProcessor, производящий актуализацию вендорных префиксов в CSS-коде. AutoprefixCssPostProcessor создан на основе популярного CSS-постпроцессора – Autoprefixer (на данный момент поддерживается версия 3.1). Я не буду объяснять для чего нужен Autoprefixer, потому что всю основную информацию о данном продукте вы можете подчеркнуть из статьи Андрея Ситника «Автопрефиксер — окончательное решение проблемы префиксов в CSS».

В этом разделе я расскажу о том, как правильно настроить BundleTransformer.Autoprefixer. Если вы не читали разделы «Постпроцессоры» и «Усовершенствованные отладочные HTTP-хэндлеры» данной статьи, то обязательно прочитайте их, т.к. в них затрагиваются многие важные моменты, связанные с работой BundleTransformer.Autoprefixer.

После установки BundleTransformer.Autoprefixer и выбора JavaScript-движка вам нужно выполнить следующие действия:

  1. Добавить постпроцессор AutoprefixCssPostProcessor в конец списка активных CSS-постпроцессоров, который задается в атрибуте defaultPostProcessors конфигурационного элемента /configuration/bundleTransformer/core/css.
  2. Зарегистрировать отладочный HTTP-хэндлер CssAssetHandler в файле Web.config (требуется для режима отладки).
  3. Зарегистрировать экземпляр класса CustomBundleResolver в качестве текущего BundleResolver`а (требуется для режима отладки).

Затем в конфигурационной секции /configuration/bundleTransformer/autoprefixer файла Web.config можно сделать необязательные настройки алгоритма Autoprefixer`а:

<configuration><bundleTransformer><autoprefixer cascade="true" safe="false">
      <browsers>
        <add conditionalExpression="> 1%" />
        <add conditionalExpression="last 2 versions" />
        <add conditionalExpression="Firefox ESR" />
        <add conditionalExpression="Opera 12.1" />
      </browsers></autoprefixer></bundleTransformer></configuration>

Подробно рассмотрим все свойства конфигурационной секции autoprefixer:

Свойство Тип данных Значение по умолчанию Описание
browsers Список условных выражений 1%,
last 2 versions,
Firefox ESR,
Opera 12.1
Содержит список условных выражений для определения подмножества поддерживаемых браузеров. Синтаксис условных выражений подробно описан в официальной документации Autoprefixer`а. Если элемент browsers не указан или пуст, то используется значение по умолчанию. Чтобы полностью отключить добавление вендорных префиксов нужно оставить в элементе browsers всего одно условное выражение равное none.
cascade Булевский true Создает визуальный каскад из префиксов следующего вида:

-webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
        box-sizing: border-box;
safe Булевский false Включает специальный безопасный режим для парсинга сломанного CSS-кода.

Bundle Transformer: Handlebars

Модуль BundleTransformer.Handlebars содержит адаптер-транслятор HandlebarsTranslator, производящий прекомпиляцию Handlebars-шаблонов в JavaScript. HandlebarsTranslator создан на основе популярного шаблонизатора – Handlebars.js (на данный момент поддерживается версия 2.0.0). Несмотря на то, что данный транслятор создан на основе шаблонизатора, он мало чем отличается от других трансляторов, дающих на выходе JavaScript-код. Файлы с кодом шаблонов (по умолчанию транслятором обрабатываются файлы с расширениями .handlebars и .hbs) нужно регистрировать в скриптовых бандлах:

using Core.Bundles;
using Core.Orderers;public class BundleConfig
{
   public static void RegisterBundles(BundleCollection bundles)
   {
      …
      var commonTemplatesBundle = new CustomScriptBundle(
         "~/Bundles/CommonTemplates");
      commonTemplatesBundle.Include("~/Scripts/handlebars/handlebars.runtime.js",
         "~/Scripts/handlebars/HandlebarsHelpers.js",
         "~/Scripts/handlebars/HandlebarsTranslatorBadge.handlebars",);
      commonTemplatesBundle.Orderer = nullOrderer;
      bundles.Add(commonTemplatesBundle);}
}

В отличие от CoffeeScript и TypeScript скомпилированные Handlebars-шаблоны требуют наличия файла handlebars.runtime.js (урезанная версия библиотеки handlebars.js, из которой исключен код необходимый для компиляции шаблонов). Этот файл можно разместить в бандле с общими библиотеками или в бандле с Handlebars-шаблонами. Главное, чтобы его объявление шло перед объявлением шаблонов.

В конфигурационной секции /configuration/bundleTransformer/handlebars файла Web.config можно произвести настройку прекомпиляции шаблонов:

<configuration><bundleTransformer><handlebars namespace="Handlebars.templates" rootPath=""
      knownHelpers="link" knownHelpersOnly="true" data="false"></handlebars></bundleTransformer></configuration>

Подробно рассмотрим все свойства конфигурационной секции handlebars:

Свойство Тип данных Значение по умолчанию Описание
namespace Строка Handlebars.templates Задает пространство имен для шаблонов.
rootPath Строка Пустая строка Задает путь к корневой директории шаблонов. Предположим, что у нас есть следующий URL шаблона — /Scripts/hbs/discussions/index.hbs. По умолчанию имя такого шаблона извлекается из имени файла — index, но если мы присвоим этому свойству значение равное /Scripts/hbs/, то получим следующее имя шаблона — discussions/index.
knownHelpers Строка Пустая строка Содержит разделенный запятыми список известных хелперов. Добавление имен хелперов в этот список позволяет оптимизировать обращения к ним, что приводит к уменьшению размера скомпилированного шаблона.
knownHelpersOnly Булевский false Разрешает использовать только известные хелперы. Если значение данного свойства равно true и код шаблона содержит вызовы хелперов, которые не являются встроенными или не объявлены в свойстве knownHelpers, то будет выдано исключение.
data Булевский true Разрешает при компиляции включать в шаблоны данные для @data-переменных (например, @index). Если в ваших шаблонах имеются итерационное блоки, но не используются @data-переменные, то лучше присвойте этому свойству значение равное false – это увеличит производительность.

Также стоит отметить, что если имя файла, содержащего код шаблона, начинается с подчеркивания, то шаблон будет скомпилирован как глобальное частичное представление (начальное подчеркивание будет удалено из имени шаблона).

Bundle Transformer: Hogan

Модуль BundleTransformer.Hogan содержит адаптер-транслятор HoganTranslator, производящий прекомпиляцию Mustache-шаблонов в JavaScript. HoganTranslator создан на основе популярного компилятора Mustache-шаблонов – Hogan.js (на данный момент поддерживается версия 3.0.2). Принципы работы BundleTransformer.Hogan во многом схожи с принципами работами BundleTransformer.Handlebars, поэтому мы рассмотрим лишь ключевые различия. Файлы с кодом шаблонов (по умолчанию транслятором обрабатываются файлы с расширением .mustache) нужно регистрировать в скриптовых бандлах:

using Core.Bundles;
using Core.Orderers;public class BundleConfig
{
   public static void RegisterBundles(BundleCollection bundles)
   {
      …
      var commonTemplatesBundle = new CustomScriptBundle(
         "~/Bundles/CommonTemplates");
      commonTemplatesBundle.Include(
         "~/Scripts/hogan/template-{version}.js",
         "~/Scripts/hogan/HoganTranslatorBadge.mustache",
         …);
      commonTemplatesBundle.Orderer = nullOrderer;
      bundles.Add(commonTemplatesBundle);}
}

Также как и в Handlebars скомпилированные шаблоны требуют наличия специальной JavaScript-библиотеки — template-3.0.2.js (в будущих релизах номер версии, скорее всего, изменится).

В конфигурационной секции /configuration/bundleTransformer/hogan файла Web.config можно произвести настройку прекомпиляции шаблонов:

<configuration><bundleTransformer><hogan useNativeMinification="false"
      variable="templates" namespace="" delimiters="">
      <sectionTags>
        <add sectionName="newWindow"
           openingTagName="_newWindow" closingTagName="newWindow" />
      </sectionTags></hogan></bundleTransformer></configuration>

Подробно рассмотрим все свойства конфигурационной секции hogan:

Свойство Тип данных Значение по умолчанию Описание
useNativeMinification Булевский false Если значение данного свойства равно true, то минимизация кода скомпилированного шаблона, будет производиться средствами транслятора.
variable Строка templates Задает имя JavaScript-переменной, в которой будут храниться шаблоны.
namespace Строка Пустая строка Задает пространство имен, которое добавляется как префикс к имени шаблона.
sectionTags Список пользовательских тегов Пустой список Содержит список пользовательских тегов, которые будут обрабатываться как секции. Например, если мы добавим пользовательскую секцию с именем отрывающегося тега _newWindow и именем закрывающегося тега newWindow, то код {{_newWindow}} target="_blank"{{/newWindow}} будет обработан компилятором без ошибок.
delimiters Строка Пустая строка Задает строку, которая переопределяет стандартные разделители. Например, если мы захотим заменить стандартные разделители в виде двойных фигурных скобок на разделители в стиле ASP, то данному свойству нужно будет присвоить следующее значение – <% %> (при добавлении в файл Web.config нужно экранировать специальные символы — &lt;% %&gt;).
Реклама
  1. Nova
    03.12.2014 в 18:38

    Андрей, спасибо за статью! Всё четко разложили по полочкам.

    Однако, при интеграции в проекте ASP.NET MVC5 + Bootstrap 3.3.1 + LESS в release режиме у меня не удаётся правильно настроить компиляцию .less-файлов Bootstrap. При запуске веб-проекта в runtime получаю следующую ошибку:
    During translation of LESS-code, readed from the file ‘/Content/bootstrap/scaffolding.less’, to CSS-code syntax error has occurred.
    See more details:

    Error type: Name
    Message: .box-sizing is undefined
    File: /Content/bootstrap/scaffolding.less
    Line number: 12
    Column number: 3
    Source error:

    Line 11: * {
    Line 12: .box-sizing(border-box);
    ————^
    Line 13: }»

    Видимо проблема в миксинах и глобальных переменных в LESS… Подскажите, пожалуйста, как быть? Может есть готовый настроенный тестовый проектик с использованием Bootstrap и LESS.
    Простые less-файлы компилируются и минифицируются хорошо. Настраивал по доке с официального сайта Bundle Transformer 1.9.32.

    p.s. Как вариант, предполагаю использовать Web Essentials для компиляции LESS для Bootstrap, а Bundle Transformer для всего остального.

  2. 03.12.2014 в 18:44

    Здравствуйте, Nova!

    Вы добавляете в бандл главный LESS-файл или все содержимое директории?

    • Nova
      03.12.2014 в 18:54

      Андрей, добрый день!
      Я добавляю главный LESS-файл:
      var cssBundle = new CustomStyleBundle(«~/bundles/css»);
      cssBundle.Include(«~/Content/Site.less»);
      cssBundle.Include(«~/Content/bootstrap/bootstrap.less»);
      cssBundle.Transforms.Add(cssTransformer);
      cssBundle.Orderer = nullOrderer;
      bundles.Add(cssBundle);

      • 03.12.2014 в 18:57

        Строка «cssBundle.Transforms.Add(cssTransformer);» является лишней.

  3. Nova
    03.12.2014 в 19:07

    Андрей, огромное вам спасибо! Работает 🙂
    Что-то я не внимательно прочитал как использовать CustomStyleBundle(), сразу пробовал через Bundle().

    • 03.12.2014 в 19:13

      Кроме того, Вы должны понимать, что файлы `Site.less` и `bootstrap/bootstrap.less` транслируются по отдельности и каждый из них видит только свои миксины и переменные. В качестве тестового проекта рекомендую Вам посмотреть WebMarkupMin.Example.Mvc — https://webmarkupmin.codeplex.com/SourceControl/latest

      Сейчас уже не стоит использовать Web Essentials в качестве LESS-компилятора. Рекомендую Вам прочитать обсуждение «Переход на Grunt/Gulp» — https://social.msdn.microsoft.com/Forums/ru-RU/121d6228-5172-40df-a1b4-3eb7f49ddccf/-gruntgulp?forum=aspnetru

      • Nova
        03.12.2014 в 19:40

        Хорошо, обязательно почитаю на досуге. Спасибо!
        Между тем, мы уже используем Grunt/Gulp для статической компиляции и минификации ресурсов при выкладывании проектов в production, а для отладки пока используем Bundle Transformer.
        Возникают резонные вопросы:
        1.) Можно ли использовать Bundle Transformer при развертывании веб-приложения в кластере (веб-ферме)?
        2.) Будет ли формируемая ссылка на bundle одинаковая на разных серверах?
        3.) При перезагрузки одного из серверов не придётся ли клиенту заново загружать ранее кешированные файлы?

  4. 03.12.2014 в 20:15

    По поводу веб-ферм: Bundle Transformer отвечает только за трансформации, а генерация ссылок и кэширование производится на уровне Microsoft ASP.NET Web Optimization Framework, поэтому ничего конкретного Вам сказать не могу. На эту тему есть обсуждение на Stack Overflow — http://stackoverflow.com/questions/21484523/bundles-caching-and-web-farms

    Вообще мне кажется, что Вам стоит подумать о хранении скриптов и стилей на CDN.

  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: