Вышел Bundle Transformer 1.6.2 или что изменилось за полгода?

в 19:49, , рубрики: .net, ASP, ASP.NET, asp.net mvc, Bundle Transformer, Bundling and Minification, coffeescript, css, CSS Optimizer, CSSO, Google Closure Compiler, javascript, JSMin, less, Packer, System.Web.Optimization, UglifyJS, WebGrease, Клиентская оптимизация, метки: , , , , , , , , , , , , , , , ,

Логотип Bundle Transformer
Bundle Transformer – это разработанное мной модульное расширение для Microsoft ASP.NET Web Optimization Framework (другие названия: ASP.NET Bundling and Minification, System.Web.Optimization, Microsoft.Web.Optimization и ASP.NET Optimization – Bundling). В апреле этого года я уже делал подробный обзор возможностей Bundle Transformer, но за это время данный продукт очень сильно изменился. Поэтому я решил написать данный обзор и рассказать об основных изменениях, которые произошли в Bundle Transformer за прошедшие полгода.

Изменения, связанные с развитием Microsoft ASP.NET Web Optimization Framework

Апрельская версия Bundle Transformer была разработана для 1-й беты Microsoft ASP.NET Web Optimization Framework (далее B/M). Уже во 2-й бете B/M произошли серьезные изменения: сильно изменился API, появилась поддержка режима отладки и была признана устаревшей возможность создания динамических bundle`ов (больше не рекомендуется использовать метод EnableDefaultBundles и класс DynamicFolderBundle). В финальной версии B/M уже не было кардинальных изменений, но добавилась одна очень полезная возможность – это поддержка CDN.

Все перечисленные выше изменения также повлияли и на Bundle Transformer.

Начиная со 2-й беты B/M рекомендуется перенести код, создающий bundle`ы, из файла Global.asax в класс BundleConfig и разместить этот класс в директории App_Start. В файле Global.asax нужно оставить только вызов метода RegisterBundles класса BundleConfig:

using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace BundleTransformer.Example.Mvc
{
	public class MvcApplication : System.Web.HttpApplication
	{
		protected void Application_Start()
		{
			AreaRegistration.RegisterAllAreas();

			FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
			RouteConfig.RegisterRoutes(RouteTable.Routes);
			// Запускаем создание bundle`ов
			BundleConfig.RegisterBundles(BundleTable.Bundles);
		}
	}
}

Рассмотрим создание bundle`ов и настройку их обработки с помощью Bundle Transformer на примере следующего класса BundleConfig:

using System.Web.Optimization;

using BundleTransformer.Core.Orderers;
using BundleTransformer.Core.Transformers;

namespace BundleTransformer.Example.Mvc
{
	public class BundleConfig
	{
		public static void RegisterBundles(BundleCollection bundles)
		{
			var cssTransformer = new CssTransformer();
			var jsTransformer = new JsTransformer();
			var nullOrderer = new NullOrderer();

			var commonStylesBundle = new Bundle("~/Bundles/CommonStyles");
			commonStylesBundle.Include(
				"~/Content/Site.css",
				"~/Content/BundleTransformer.css",
				"~/AlternativeContent/css/TestCssComponentsPaths.css",
				"~/Content/themes/base/jquery.ui.core.css",
				"~/Content/themes/base/jquery.ui.theme.css",
				"~/Content/themes/base/jquery.ui.resizable.css",
				"~/Content/themes/base/jquery.ui.button.css",
				"~/Content/themes/base/jquery.ui.dialog.css",
				"~/Content/TestTranslators.css",
				"~/Content/TestLess.less",
				"~/Content/TestSass.sass",
				"~/Content/TestScss.scss");
			commonStylesBundle.Transforms.Add(cssTransformer);
			commonStylesBundle.Orderer = nullOrderer;

			bundles.Add(commonStylesBundle);

			var modernizrBundle = new Bundle("~/Bundles/Modernizr");
			modernizrBundle.Include("~/Scripts/modernizr-2.*");
			modernizrBundle.Transforms.Add(jsTransformer);
			modernizrBundle.Orderer = nullOrderer;

			bundles.Add(modernizrBundle);

			var commonScriptsBundle = new Bundle("~/Bundles/CommonScripts");
			commonScriptsBundle.Include("~/Scripts/MicrosoftAjax.js",
				"~/Scripts/jquery-{version}.js",
				"~/Scripts/jquery-ui-{version}.js",
				"~/Scripts/jquery.validate.js",
				"~/Scripts/jquery.validate.unobtrusive.js",
				"~/Scripts/jquery.unobtrusive-ajax.js",
				"~/Scripts/knockout-2.*",
				"~/Scripts/TestCoffeeScript.coffee");
			commonScriptsBundle.Transforms.Add(jsTransformer);
			commonScriptsBundle.Orderer = nullOrderer;

			bundles.Add(commonScriptsBundle);

			var jqueryUiStylesDirectoryBundle = new Bundle("~/Bundles/JqueryUiStylesDirectory");
			jqueryUiStylesDirectoryBundle.IncludeDirectory("~/Content/themes/base/", "*.css");
			jqueryUiStylesDirectoryBundle.Transforms.Add(new CssTransformer(
				new[] { "*.all.css", "jquery.ui.base.css" }));

			bundles.Add(jqueryUiStylesDirectoryBundle);

			var scriptsDirectoryBundle = new Bundle("~/Bundles/ScriptsDirectory");
			scriptsDirectoryBundle.IncludeDirectory("~/Scripts/", "*.js");
			scriptsDirectoryBundle.Transforms.Add(new JsTransformer(
				new[] { "*.all.js", "references.js" }));

			bundles.Add(scriptsDirectoryBundle);
		}
	}
}

Главное отличие по сравнению с 1-й бетой B/M заключается в том, что для добавления файлов и директорий теперь используются методы Include и IncludeDirectory (вместо методов AddFile и AddDirectory). Кроме того, добавление трансформаций теперь производится не через конструктор класса Bundle, а через его свойство Transforms (в приведенном выше коде вы можете увидеть это на примере добавления экземпляров классов CssTransformer и JsTransformer).

Стоит отметить, что помимо класса Bundle для создания bundle`ов могут также использоваться его подклассы StyleBundle (для стилей) и ScriptBundle (для скриптов). В эти классы уже добавлены трансформации, отвечающие за минимизацию кода (экземпляры классов CssMinify и JsMinify). В нашем случае мы не можем использовать эти подклассы, потому что нам необходимо вместо экземпляров классов CssMinify и JsMinify добавить трансформации из Bundle Transformer (экземпляры классов CssTransformer и JsTransformer).

Рассмотрим регистрацию ссылок на созданные bundlе`ы в коде представлений на примере файла _Layout.cshtml:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Bundle Transformer Example MVC Application</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
		@Styles.Render("~/Bundles/CommonStyles")
		@Scripts.Render("~/Bundles/Modernizr")
		...
    </head>
    <body>
		...
		@Scripts.Render("~/Bundles/CommonScripts")
        @RenderSection("scripts", required: false)
    </body>
</html>

Теперь ссылки на bundle`ы добавляются в код представления с помощью метода Render (Styles.Render используется для CSS, а Scripts.Render для JavaScript). Использование метода Render не только делает добавление ссылок на bundle`ы более удобным, но и решает главную проблему ранних версий B/M – поддержку режима отладки.

B/M определяет режим, в котором находится веб-приложение, на основе следующих настроек:

  1. Значения атрибута debug элемента compilation из файла Web.config (true – режим отладки; false – режим выпуска);
  2. Значения свойства BundleTable.EnableOptimizations, которое можно указать в классе BundleConfig (true – режим выпуска; false – режим отладки). Причем значение свойства BundleTable.EnableOptimizations имеет приоритет над настройками из файла Web.config.

В режиме выпуска код файлов, входящих в bundle, объединяется и обрабатывается (применяются трансформации). На выходе получается HTML-код следующего вида:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Home Page - Bundle Transformer Example MVC Application</title>
        <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
		<link href="/Bundles/CommonStyles?v=IWN75r8IOIWnlehQ6JVPUgrb7UER075iobpzbjYTtRQ1" rel="stylesheet"/>
		<script src="/Bundles/Modernizr?v=1dm47T0PPFmcdy8ssp2EZ4h8yT2SjNhVvtdbc0MyDAs1"></script>
		...
    </head>
    <body>
		...
		<script src="/Bundles/CommonScripts?v=qWsyReB8UFAt-HPS-6MCkeDDTs2lQgYMdyCUd2V9O4o1"></script>        
    </body>
</html>

А в режиме отладки файлы, входящие в bundle, выводятся в исходном виде и по отдельности:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Home Page - Bundle Transformer Example MVC Application</title>
        <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
		<link href="/Content/Site.css" rel="stylesheet"/>
		<link href="/Content/BundleTransformer.css" rel="stylesheet"/>
		<link href="/AlternativeContent/css/TestCssComponentsPaths.css" rel="stylesheet"/>
		<link href="/Content/themes/base/jquery.ui.core.css" rel="stylesheet"/>
		<link href="/Content/themes/base/jquery.ui.theme.css" rel="stylesheet"/>
		<link href="/Content/themes/base/jquery.ui.resizable.css" rel="stylesheet"/>
		<link href="/Content/themes/base/jquery.ui.button.css" rel="stylesheet"/>
		<link href="/Content/themes/base/jquery.ui.dialog.css" rel="stylesheet"/>
		<link href="/Content/TestTranslators.css" rel="stylesheet"/>
		<link href="/Content/TestLess.less" rel="stylesheet"/>
		<link href="/Content/TestSass.sass" rel="stylesheet"/>
		<link href="/Content/TestScss.scss" rel="stylesheet"/>
		<script src="/Scripts/modernizr-2.5.3.js"></script>
		...
    </head>
    <body>
		...
		<script src="/Scripts/MicrosoftAjax.debug.js"></script>
		<script src="/Scripts/jquery-1.8.1.js"></script>
		<script src="/Scripts/jquery-ui-1.8.23.js"></script>
		<script src="/Scripts/jquery.validate.js"></script>
		<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
		<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
		<script src="/Scripts/knockout-2.1.0.debug.js"></script>
		<script src="/Scripts/TestCoffeeScript.coffee"></script>        
    </body>
</html>

Что существенно упрощает отладку клиентского кода.

Но если вы используете препроцессоры, то при работе в режиме отладки у вас могут возникнуть проблемы. В приведенном выше коде присутствуют ссылки на файлы с расширениями .less, .sass, .scss и .coffee. Если в файле Web.config для этих расширений не зарегистрированы HTTP-хэндлеры, то содержимое этих файлов окажется необработанным и могут возникнуть ошибки на стороне клиента.

Для решения данной проблемы в библиотеки трансляторов BundleTransformer.Less, BundleTransformer.LessLite, BundleTransformer.SassAndScss и BundleTransformer.CoffeeScript были добавлены реализации соответствующих HTTP-хэндлеров. При установке трансляторов через NuGet HTTP-хэндлеры регистрируются в файле Web.config автоматически:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	...
	<system.web>
	...
		<httpHandlers>
			<!-- Declaration of Bundle Transformer HTTP-handlers -->
			<add path="*.less" verb="GET" 
				type="BundleTransformer.LessLite.HttpHandlers.LessAssetHandler, BundleTransformer.LessLite" />
			<add path="*.sass" verb="GET" 
				type="BundleTransformer.SassAndScss.HttpHandlers.SassAndScssAssetHandler, BundleTransformer.SassAndScss" />
			<add path="*.scss" verb="GET" 
				type="BundleTransformer.SassAndScss.HttpHandlers.SassAndScssAssetHandler, BundleTransformer.SassAndScss" />
			<add path="*.coffee" verb="GET" 
				type="BundleTransformer.CoffeeScript.HttpHandlers.CoffeeScriptAssetHandler, BundleTransformer.CoffeeScript" />
			<!-- /Declaration of Bundle Transformer HTTP-handlers -->
		</httpHandlers>
	</system.web>
	<system.webServer>
		...
		<handlers>
			...
			<!-- Declaration of Bundle Transformer HTTP-handlers -->
			<add name="LessAssetHandler" path="*.less" verb="GET" 
				type="BundleTransformer.LessLite.HttpHandlers.LessAssetHandler, BundleTransformer.LessLite" 
				resourceType="File" preCondition="" />
			<add name="SassAssetHandler" path="*.sass" verb="GET" 
				type="BundleTransformer.SassAndScss.HttpHandlers.SassAndScssAssetHandler, BundleTransformer.SassAndScss" 
				resourceType="File" preCondition="" />
			<add name="ScssAssetHandler" path="*.scss" verb="GET" 
				type="BundleTransformer.SassAndScss.HttpHandlers.SassAndScssAssetHandler, BundleTransformer.SassAndScss" 
				resourceType="File" preCondition="" />
			<add name="CoffeeScriptAssetHandler" path="*.coffee" verb="GET" 
				type="BundleTransformer.CoffeeScript.HttpHandlers.CoffeeScriptAssetHandler, BundleTransformer.CoffeeScript" 
				resourceType="File" preCondition="" />
			<!-- /Declaration of Bundle Transformer HTTP-handlers -->
		</handlers>
	</system.webServer>
	...
</configuration>

Исключение составляет лишь NuGet-пакет BundleTransformer.Less: при его установке также устанавливается пакет dotless, который автоматически регистрирует свою версию HTTP-хэндлера для обработки файлов с расширением .less. Но у вас всегда есть возможность вручную заменить его на HTTP-хэндлер LessAssetHandler из BundleTransformer.Less.

Управлять настройками родных HTTP-хэдлеров трансляторов можно с помощью конфигурационного элемента /configuration/bundleTransformer/core/assetHandler из файла Web.config. В следующем коде показаны настройки HTTP-хэндлеров по умолчанию:

<configuration>
	...
	<bundleTransformer xmlns="http://tempuri.org/BundleTransformer.Configuration.xsd">
		<core>
			...
			<assetHandler clientCacheDurationInDays="365" enableCompression="true"
				useLastModifiedHeader="true" useETagHeader="true"
				serverCacheDurationInMinutes="15" useServerCacheSlidingExpiration="false"
				disableClientCacheInDebugMode="true" disableCompressionInDebugMode="true" />
			...
		</core>
	</bundleTransformer>
	...
</configuration>

где,

  • clientCacheDurationInDays="(число)". Задает продолжительность нахождения текстового содержимого обработанного файла в кэше браузера (в днях).
  • enableCompression="(true|false)". Включает GZIP/Deflate-сжатие обработанного файла.
  • useLastModifiedHeader="(true|false)". Разрешает использовать HTTP-заголовок Last-Modified для оповещения браузера об изменении обработанного файла.
  • useETagHeader="(true|false)". Разрешает использовать HTTP-заголовок ETag для оповещения браузера об изменении обработанного файла.
  • serverCacheDurationInMinutes="(число)". Задает продолжительность нахождения текстового содержимого обработанного файла в серверном кэше (в минутах).
  • useServerCacheSlidingExpiration="(true|false)". Разрешает использование скользящего времени устаревания элемента серверного кэша.
  • disableClientCacheInDebugMode="(true|false)". Отключает в режиме отладки браузерное кэширование обработанного файла.
  • disableCompressionInDebugMode="(true|false)". Отключает в режиме отладки GZIP/Deflate-сжатие обработанного файла.

Трансляторы

Bundle Transformer: LESS Lite

В конце апреля появилась облегченная версия библиотеки dotless под названием DotlessClientOnly. Данная библиотека содержит только LESS-компилятор, а весь функционал, связанный с ASP.NET, из нее был удален (например, HTTP-хэндлер).

BundleTransformer.LessLite использует возможности DotlessClientOnly для трансляции LESS-кода в CSS. По возможностям и программному интерфейсу BundleTransformer.LessLite полностью эквивалентен BundleTransformer.Less. Поэтому если в ваших проектах вся работа с LESS производится только через Bundle Transformer, то лучше использовать модуль BundleTransformer.LessLite, т.к. в его основе лежит более легковесная библиотека.

Bundle Transformer: CoffeeScript

До версии 1.5.5 в BundleTransformer.CoffeeScript для трансляции CoffeeScript-кода в JavaScript использовалась библиотека SassAndCoffee.JavaScript версии 2.0.2.0. К сожалению, библиотека SassAndCoffee.JavaScript уже давно не развивается и поддерживает уже устаревшую версию CoffeeScript (версия 1.1.3). Поэтому в новых версиях BundleTransformer.CoffeeScript от нее пришлось отказаться и реализовать собственный компилятор, поддерживающий CoffeeScript 1.3.3.

Минимизаторы

Основной задачей при создании Bundle Transformer было предоставить разработчику возможность выбора из нескольких минимизаторов. В ранних версиях продукта разработчику были доступны адаптеры лишь для 2-х семейств минимизаторов: Microsoft Ajax Minifier и YUI Compressor. В текущей же версии доступны адаптеры практически для всех популярных минимизаторов CSS- и JS-кода.

Bundle Transformer: Closure

BundleTransformer.Closure содержит 2 минимизатора JS-кода: ClosureRemoteJsMinifier и ClosureLocalJsMinifier. ClosureRemoteJsMinifier производит минимизацию с помощью веб-сервиса Google Closure Compiler Service API и требует постоянного подключения к Интернету. ClosureLocalJsMinifier осуществляет минимизацию средствами консольного приложения Google Closure Compiler Application, и требует для своей работы: виртуальную машину Java и последнюю версию файла compiler.jar.

Bundle Transformer: JSMin

BundleTransformer.JsMin содержит адаптер-минимизатор JS-кода CrockfordJsMinifier. CrockfordJsMinifier основан на C#-порте старейшего минимизатора JS-кода – JSMin, который был написан Дугласом Крокфордом (Douglas Crockford). Используемый C#-порт был создан на основе версии JSMin от 22 мая 2007 года.

Bundle Transformer: UglifyJS

BundleTransformer.UglifyJs содержит адаптер-минимизатор JS-кода UglifyJsMinifier. UglifyJsMinifier создан на основе популярного в сообществе Node.js минимизатора JS-кода — UglifyJS (сейчас поддерживается версия 1.3.3).

Bundle Transformer: Packer

BundleTransformer.Packer содержит адаптер-минимизатор JS-кода EdwardsJsMinifier. EdwardsJsMinifier создан на основе JS-минимизатора Дина Эдвардса (Dean Edwards) Packer версии 3.0. Главной особенностью Packer`а является то, что помимо минимизации и обфускации кода, он может еще производить сжатие кода с помощью алгоритма Base62. Base62-сжатие можно использовать, когда на веб-сервере отсутствует поддержка GZIP/Deflate-сжатия.

Bundle Transformer: CSSO

BundleTransformer.Csso содержит адаптер-минимизатор CSS-кода KryzhanovskyCssMinifier. KryzhanovskyCssMinifier основан на CSS-минимизаторе CSSO (сейчас поддерживается версия 1.2.18). Данный минимизатор был создан разработчиками методологии БЭМ: Сергеем Крыжановским и Виталием Харисовым. Главным отличием данного CSS-минимизатора от других средств минимизации CSS-кода — является поддержка структурной минимизации (например, с CSS-кодом производятся следующие операции: слияние блоков с одинаковыми селекторами, удаление перекрываемых свойств, частичное выделение свойств в отдельный блок, частичное слияние блоков и т.д.). Структурная минимизация дает высокую степень сжатия при минимизации кода сгенерированного «машиной» (например, препроцессором).

Хочу отметить один важный момент: CSSO написан на ECMAScript 5 и я очень долго не мог найти JS-движок для .NET, который мог бы правильно выполнить код этой библиотеки. В итоге я остановил свой выбор на реализации JS-движка V8 под .NET — Noesis Javascript .NET. Данный движок частично написан на неуправляемом коде и имеет 2 версии: 32- и 64-разрядную. Из-за этой особенности реализации модуль BundleTransformer.Csso был разделен на 2 NuGet-пакета: BundleTransformer.Csso.x86 и BundleTransformer.Csso.x64. Для корректной работы Noesis Javascript .NET требуются сборки msvcp100.dll и msvcr100.dll из Microsoft Visual C++ 2010. Если в вашей системе нет этих сборок, то рекомендую вам установить Microsoft Visual C++ 2010 Redistributable Package (x86, x64).

Bundle Transformer: WebGrease

BundleTransformer.WG содержит адаптер-минимизатор CSS-кода WgCssMinifier. WgCssMinifier производит минимизацию CSS-кода с помощью семантического CSS-минимизатора из разработанной Microsoft библиотеки WebGrease. Семантический CSS-минимизатор WebGrease также, как и CSSO производит структурную минимизацию CSS-кода.

В данный момент, NuGet-пакет BundleTransformer.WG имеет статус альфа, т.к. текущая версия WebGrease (версия 1.1.0) содержит ошибку и из-за этого не может использоваться в производственных версиях сайтов.

Если вы хотите узнать больше о данном минимизаторе, то рекомендую вам посмотреть видео-доклад Говарда Дёркинга «Bundling and Optimizing».

Рекомендации по применению минимизаторов

Наиболее надежными минимизаторами являются минимизаторы из первой тройки: Microsoft Ajax Minifier, YUI Compressor и Google Closure Compiler (лидер по степени сжатия JS-кода). Все они обладают хорошей степенью сжатия, а обработанный ими код практически не содержит ошибок.

Новые минимизаторы, которые были разработаны под Node.js: UglifyJS и CSSO, дают более высокую степень сжатия, чем минимизаторы первой тройки (UglifyJS в некоторых случаях сжимает лучше, чем Google Closure Compiler в режиме Simple), но пока еще не обладают таким уровнем надежности.

Самые старые минимизаторы: JSMin и Packer, сейчас годятся только для сжатия самого простого JS-кода. К сожалению, они проигрывают современным минимизаторам и по степени сжатия, и по уровню надежности.

Я не сравнивал семантический минимизатор CSS-кода WebGrease с другими минимизаторами из-за специфики ошибки, содержащейся в нем. Но по общим наблюдениям, мне кажется, что он обладает большей степенью сжатия кода, чем CSSO.

Настройки

Текущие настройки Bundle Transformer эквивалентны следующему варианту файла Web.config (в случае, когда установлены все дополнительные модули):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<configSections>
		<!-- Declaration of Bundle Transformer configuration section group -->
		<sectionGroup name="bundleTransformer">
			<section name="core" type="BundleTransformer.Core.Configuration.CoreSettings" />
			<section name="less" 
				type="BundleTransformer.LessLite.Configuration.LessLiteSettings" />
			<section name="sassAndScss" 
				type="BundleTransformer.SassAndScss.Configuration.SassAndScssSettings" />
			<section name="microsoftAjax"
				type="BundleTransformer.MicrosoftAjax.Configuration.MicrosoftAjaxSettings" />
			<section name="yui" type="BundleTransformer.Yui.Configuration.YuiSettings" />
			<section name="closure" 
				type="BundleTransformer.Closure.Configuration.ClosureSettings" />
			<section name="uglify" 
				type="BundleTransformer.UglifyJs.Configuration.UglifySettings" />
			<section name="packer" 
				type="BundleTransformer.Packer.Configuration.PackerSettings" />
			<section name="csso" type="BundleTransformer.Csso.Configuration.CssoSettings" />
		</sectionGroup>
		<!-- /Declaration of Bundle Transformer configuration section group -->
		...
	</configSections>
	...
	<!-- Bundle Transformer configuration settings -->
	<bundleTransformer xmlns="http://tempuri.org/BundleTransformer.Configuration.xsd">
		<core enableTracing="false" 
			jsFilesWithMicrosoftStyleExtensions="MicrosoftAjax.js,MicrosoftMvcAjax.js, MicrosoftMvcValidation.js,knockout-$version$.js"
			useEnableOptimizationsProperty="true">
			<css defaultMinifier="NullMinifier">
				<minifiers>
					<add name="NullMinifier" 
						type="BundleTransformer.Core.Minifiers.NullMinifier, BundleTransformer.Core" />
					<add name="MicrosoftAjaxCssMinifier"
						type="BundleTransformer.MicrosoftAjax.Minifiers.MicrosoftAjaxCssMinifier, BundleTransformer.MicrosoftAjax" />
					<add name="YuiCssMinifier" 
						type="BundleTransformer.Yui.Minifiers.YuiCssMinifier, BundleTransformer.Yui" />
					<add name="KryzhanovskyCssMinifier" 
						type="BundleTransformer.Csso.Minifiers.KryzhanovskyCssMinifier, BundleTransformer.Csso" />
					<add name="WgCssMinifier" 
						type="BundleTransformer.WG.Minifiers.WgCssMinifier, BundleTransformer.WG" />
				</minifiers>
				<translators>
					<add name="NullTranslator"
						type="BundleTransformer.Core.Translators.NullTranslator, BundleTransformer.Core" 
						enabled="false" />
					<add name="LessTranslator" 
						type="BundleTransformer.LessLite.Translators.LessTranslator, BundleTransformer.LessLite"
						enabled="true" />
					<add name="SassAndScssTranslator"
						type="BundleTransformer.SassAndScss.Translators.SassAndScssTranslator, BundleTransformer.SassAndScss" 
						enabled="true" />
				</translators>
			</css>
			<js defaultMinifier="NullMinifier">
				<minifiers>
					<add name="NullMinifier"
						type="BundleTransformer.Core.Minifiers.NullMinifier, BundleTransformer.Core" />
					<add name="MicrosoftAjaxJsMinifier"
						type="BundleTransformer.MicrosoftAjax.Minifiers.MicrosoftAjaxJsMinifier, BundleTransformer.MicrosoftAjax" />
					<add name="YuiJsMinifier" 
						type="BundleTransformer.Yui.Minifiers.YuiJsMinifier, BundleTransformer.Yui" />
					<add name="ClosureRemoteJsMinifier" 
						type="BundleTransformer.Closure.Minifiers.ClosureRemoteJsMinifier, BundleTransformer.Closure" />
					<add name="ClosureLocalJsMinifier"
						type="BundleTransformer.Closure.Minifiers.ClosureLocalJsMinifier, BundleTransformer.Closure" />
					<add name="CrockfordJsMinifier"
						type="BundleTransformer.JsMin.Minifiers.CrockfordJsMinifier, BundleTransformer.JsMin" />
					<add name="UglifyJsMinifier" 
						type="BundleTransformer.UglifyJs.Minifiers.UglifyJsMinifier, BundleTransformer.UglifyJs" />
					<add name="EdwardsJsMinifier" 
						type="BundleTransformer.Packer.Minifiers.EdwardsJsMinifier, BundleTransformer.Packer" />
				</minifiers>
				<translators>
					<add name="NullTranslator"
						type="BundleTransformer.Core.Translators.NullTranslator, BundleTransformer.Core" 
						enabled="false" />
					<add name="CoffeeScriptTranslator" 
						type="BundleTransformer.CoffeeScript.Translators.CoffeeScriptTranslator, BundleTransformer.CoffeeScript" 
						enabled="true" />
				</translators>
			</js>
			<assetHandler clientCacheDurationInDays="365" enableCompression="true"
				useLastModifiedHeader="true" useETagHeader="true"
				serverCacheDurationInMinutes="15" useServerCacheSlidingExpiration="false"
				disableClientCacheInDebugMode="true" disableCompressionInDebugMode="true" />
		</core>
		<less useNativeMinification="false" severity="0" />
		<sassAndScss useNativeMinification="false" />
		<microsoftAjax>
			<css allowEmbeddedAspNetBlocks="false" colorNames="Strict" commentMode="Important" 
				ignoreErrorList="" indentSize="4" minifyExpressions="true" 
				outputMode="SingleLine" blocksStartOnSameLine="NewLine" preprocessorDefineList="" 
				termSemicolons="false" severity="0" />
			<js allowEmbeddedAspNetBlocks="false" collapseToLiteral="true" 
				debugLookupList="Debug,$Debug,WAssert,Msn.Debug,Web.Debug" 
				evalTreatment="Ignore" ignoreConditionalCompilation="false" ignoreErrorList="" 
				indentSize="4" inlineSafeStrings="true" knownGlobalNamesList="" 
				localRenaming="CrunchAll" macSafariQuirks="true" minifyCode="true" 
				noAutoRenameList="$super" outputMode="SingleLine" blocksStartOnSameLine="NewLine"
				preprocessorDefineList="" preserveFunctionNames="false" 
				preserveImportantComments="true" removeFunctionExpressionNames="true" 
				removeUnneededCode="true" renamePairs="" strictMode="false" 
				stripDebugStatements="true" termSemicolons="false" severity="0"/>
		</microsoftAjax>
		<yui>
			<css compressionType="Standard" removeComments="true"
				lineBreakPosition="-1" />
			<js compressionType="Standard" obfuscateJavascript="true"
				preserveAllSemicolons="false" disableOptimizations="false"
				ignoreEval="false" severity="0" lineBreakPosition="-1"
				encoding="UTF8" threadCulture="en-us" />
		</yui>
		<closure>
			<js>
				<remote 
					closureCompilerServiceApiUrl="http://closure-compiler.appspot.com/compile" 
					compilationLevel="Simple" prettyPrint="false" excludeDefaultExterns="false" 
					severity="0" />
				<local 
					javaVirtualMachinePath="" closureCompilerApplicationPath="" 
					compilationLevel="Simple" prettyPrint="false" 
					languageSpec="EcmaScript3" thirdParty="true"
					processJqueryPrimitives="false" processClosurePrimitives="false"
					severity="0" />
			</js>
		</closure>
		<uglify>
			<js>
				<parser strictSemicolons="false" />
				<mangler mangle="true" topLevel="false" defines="" 
					except="" noFunctions="false" />
				<squeezer makeSequences="true" deadCode="true" unsafe="false" />
				<codeGenerator beautify="false" indentStart="0" indentLevel="4" 
					quoteKeys="false" spaceColon="false" asciiOnly="false" />
			</js>
		</uglify>
		<packer>
			<js shrinkVariables="true" base62Encode="false" />
		</packer>
		<csso>
			<css disableRestructuring="false" />
		</csso>
	</bundleTransformer>
	<!-- /Bundle Transformer configuration settings -->
	...
</configuration>

В предыдущем обзоре я уже описывал структуру конфигурационной секции bundleTransformer, поэтому на этот раз ограничусь лишь перечислением новых секций:

  • closure – настройки модуля BundleTransformer.Closure
  • uglify – настройки модуля BundleTransformer.UglifyJs
  • packer – настройки модуля BundleTransformer.Packer
  • csso – настройки модуля BundleTransformer.Csso

Названия и возможные значения свойств перечисленных выше конфигурационных секций также не нуждаются в пояснениях, т.к. практически полностью совпадают с конфигурационными свойствами исходных минимизаторов. Также напоминаю, что для конфигурационной секции bundleTransformer реализована поддержка IntelliSense:

Поддержка IntelliSense при редактировании конфигурационной секции bundleTransformer в файле Web.config

Заключение

В заключении я хотел бы отметить некоторые важные моменты, касающиеся B/M и Bundle Transformer.

Многие считают, что B/M может работать только с ASP.NET MVC, но это не так. Вы можете использовать B/M и в других ASP.NET-фреймворках: Web Forms и Web Pages (в разделе ссылки указаны статьи, в которых рассказывается, как это можно сделать).

Текущие версии B/M и Bundle Transformer написаны под .NET Framework 4.0, поэтому ничто не мешает вам использовать их в ASP.NET MVC 3 и ASP.NET Web Forms 4.0.

Ссылки

  1. Страница Bundle Transformer на CodePlex
  2. Страница Microsoft ASP.NET Web Optimization Framework на CodePlex
  3. Видео-доклад Говарда Дёркинга «Bundling and Optimizing»
  4. Видео-доклад Говарда Дёркинга «Build high-performing HTML 5 applications easily with ASP.NET 4.5»
  5. Учебник Рика Андерсона «Bundling and Minification»
  6. Статья Рика Андерсона «Adding Bundling and Minification to Web Forms» (перевод)
  7. Статья Рика Андерсона «Adding Web Optimization to a Web Pages Site» (перевод)
  8. Статья Говарда Дёркинга «Keeping in touch with the Web optimization team»

Автор: Taritsyn

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js