Bundle Transformer 1.3.1 Beta

Bundle Transformer Beta 1 logo

Bundle Transformer - a modular extension for System.Web.Optimization (also known as the ASP.NET Bundling and Minification). Classes CssTransformer and JsTransformer, included in the core of Bundle Transformer, implement interface IBundleTransform. They are intended to replace the standard classes CssMinify and JsMinify.

The main differences classes CssTransformer and JsTransformer from standard implementations: support for debugging (in debug mode disabled code minification), automatic removal of duplicate assets, ability to exclude unnecessary assets when adding assets from a directory, support processing of JS-files with *.debug.js extensions, does not produce the re-minification of code of pre-minified assets, support automatic transformation of relative paths to absolute in CSS-code (for CssTransformer), etc. These classes do not produce the minification of code in runtime, but this feature can be added by installing of minifier-adapter (now available adapters based on Microsoft Ajax Minifier, YUI Compressor for .NET, Google Closure Compiler and Douglas Crockford's JSMin). In addition, you can also install translator-adapters that implement the translation of code on intermediate languages (LESS, Sass, SCSS and CoffeeScript).

This extension will help your web applications successfully pass a most part of the tests in YSlow.

Installing NuGet-packages

The latest version of the Bundle Transformer is written for a pre-release version of the ASP.NET Bundling and Minification (System.Web.Optimization 1.0.0 Beta) and therefore is itself in beta status. Unfortunately, installation process of the pre-release versions of libraries through NuGet differs from the process of installation of the final versions. Before the release of NuGet 1.7 installing the pre-release versions is possible only through the Package Manager Console:

Installing NuGet-package BundleTransformer.MicrosoftAjax by using the Package Manager Console

When you install the pre-release version of library, you must always specify the key -Pre:

PM> Install-Package BundleTransformer.MicrosoftAjax -Pre

When updating such libraries, also need to specify the key -Pre:

PM> Update-Package BundleTransformer.MicrosoftAjax -Pre

Starting with NuGet 1.7 added the ability to install pre-release versions of the libraries with help of dialog box the Manage NuGet Packages. In this dialog box appeared drop-down list, where you can choose to display mode of pre-release versions:

The displays of the pre-release versions of libraries in the dialog box Manage NuGet Packages

Examples of usage

Here an example of registration of assets and configuration of their processing with the help of CssTransformer and JsTransformer in the Global.asax file:

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

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

public class MvcApplication : System.Web.HttpApplication
{
   ...
   protected void Application_Start()
   {
      ...
      var cssTransformer = new CssTransformer();
      var jsTransformer = new JsTransformer();
      var nullOrderer = new NullOrderer();

      var commonStylesBundle = new Bundle("~/CommonStyles", cssTransformer);
      commonStylesBundle.AddFile("~/Content/Site.css");
      commonStylesBundle.AddFile("~/AlternativeContent/css/TestCssComponentsPaths.css");
      commonStylesBundle.AddFile("~/Content/themes/base/jquery.ui.core.css");
      commonStylesBundle.AddFile("~/Content/themes/base/jquery.ui.theme.css");
      commonStylesBundle.AddFile("~/Content/themes/base/jquery.ui.resizable.css");
      commonStylesBundle.AddFile("~/Content/themes/base/jquery.ui.button.css");
      commonStylesBundle.AddFile("~/Content/themes/base/jquery.ui.dialog.css");
      commonStylesBundle.Orderer = nullOrderer;

      BundleTable.Bundles.Add(commonStylesBundle);

      var modernizrBundle = new Bundle("~/Modernizr", jsTransformer);
      modernizrBundle.AddFile("~/Scripts/modernizr-2.0.6-development-only.js");
      modernizrBundle.Orderer = nullOrderer;

      BundleTable.Bundles.Add(modernizrBundle);

      var commonScriptsBundle = new Bundle("~/CommonScripts", jsTransformer);
      commonScriptsBundle.AddFile("~/Scripts/MicrosoftAjax.js");
      commonScriptsBundle.AddFile("~/Scripts/jquery-1.6.2.js");
      commonScriptsBundle.AddFile("~/Scripts/jquery-ui-1.8.11.js");
      commonScriptsBundle.AddFile("~/Scripts/jquery.validate.js");
      commonScriptsBundle.AddFile("~/Scripts/jquery.validate.unobtrusive.js");
      commonScriptsBundle.AddFile("~/Scripts/jquery.unobtrusive-ajax.js");
      commonScriptsBundle.AddFile("~/Scripts/knockout-2.0.0.js");
      commonScriptsBundle.AddFile("~/Scripts/AjaxLogin.js");
      commonScriptsBundle.Orderer = nullOrderer;

      BundleTable.Bundles.Add(commonScriptsBundle);
   }
}

Example of _Layout.cshtml:

@using System.Web.Optimization

<!DOCTYPE html>
<html>
   <head>
      ...
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/CommonStyles")" rel="stylesheet" type="text/css" />
      <script src="@BundleTable.Bundles.ResolveBundleUrl("~/Modernizr")"></script>
      ...
   </head>
   <body>
      ...
      <script src="@BundleTable.Bundles.ResolveBundleUrl("~/CommonScripts")"></script>
   </body>
</html>

Classes CssTransformer and JsTransformer produce processing of CSS- and JavaScript-files. Class NullOrderer disables the built-in sorting mechanism and save assets sorted in the order they are declared.

When adding assets from directory, you can specify patterns for exclusion of unnecessary files (ignorePatterns parameter):

var jqueryUiStylesDirectoryBundle = new Bundle("~/JqueryUiStylesDirectory", 
new
CssTransformer(new[] { "*.all.css", "jquery.ui.base.css" })); jqueryUiStylesDirectoryBundle.AddDirectory("~/Content/themes/base/", "*.css"); BundleTable.Bundles.Add(jqueryUiStylesDirectoryBundle); var scriptsDirectoryBundle = new Bundle("~/ScriptsDirectory",
new
JsTransformer(new[] { "*.all.js", "_references.js" })); scriptsDirectoryBundle.AddDirectory("~/Scripts/", "*.js"); BundleTable.Bundles.Add(scriptsDirectoryBundle);

Also I will give an example of creating a dynamic bundles. In the Global.asax file register suffixes of dynamic bundles:

DynamicFolderBundle css = new DynamicFolderBundle("css",
   new CssTransformer(new[] { "*.all.css", "jquery.ui.base.css" }), "*.css");
BundleTable.Bundles.Add(css);

DynamicFolderBundle js = new DynamicFolderBundle("js",
   new JsTransformer(new[] { "*.all.js", "_references.js" }), "*.js");
BundleTable.Bundles.Add(js);

DynamicFolderBundle less = new DynamicFolderBundle("less", 
   new CssTransformer(new[] { "TestLessImport.less" }), "*.less");
BundleTable.Bundles.Add(less);

DynamicFolderBundle sass = new DynamicFolderBundle("sass",
   new CssTransformer(new[] { "TestSassImport.sass" }), "*.sass");
BundleTable.Bundles.Add(sass);

DynamicFolderBundle scss = new DynamicFolderBundle("scss",
   new CssTransformer(new[] { "TestScssImport.scss" }), "*.scss");
BundleTable.Bundles.Add(scss);

DynamicFolderBundle coffee = new DynamicFolderBundle("coffee", 
   new JsTransformer(), "*.coffee");
BundleTable.Bundles.Add(coffee);

Now you can use a suffixes of dynamic bundles, when specifying paths in the link and script tags in a file _Layout.cshtml:

@using System.Web.Optimization

<!DOCTYPE html>
<html>
   <head>
      ...
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" rel="stylesheet" type="text/css" />
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/AlternativeContent/css/css")" rel="stylesheet" type="text/css" />
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/Content/themes/base/css")" rel="stylesheet" type="text/css" />
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/Content/less")" rel="stylesheet" type="text/css" />
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/Content/sass")" rel="stylesheet" type="text/css" />
      <link href="@BundleTable.Bundles.ResolveBundleUrl("~/Content/scss")" rel="stylesheet" type="text/css" />
      <script src="@BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>
      ...
   </head>
   <body>
      ...   
      <script src="@BundleTable.Bundles.ResolveBundleUrl("~/Scripts/coffee")"></script>
   </body>
</html>

Superior debugging process

Bundle Transformer considers which mode running a web application (debug or release). In debug mode is not performed minification code of assets.

Mode of an ASP.NET application is specified in Web.config file:

<system.web>
   <compilation debug="false" targetFramework="4.0">
   ...

Value of the debug attribute specifies mode in which is web application: true - debug or false - release.

For convenience of development classes CssTransformer and JsTransformer supports methods, imitating the local switching mode of web application: ForceDebugMode (to debug mode) and ForceReleaseMode (to release mode).

var jsTransformer = new JsTransformer();
jsTransformer.ForceReleaseMode();

var cssTransformer = new CssTransformer();
cssTransformer.ForceDebugMode();
...

Method ForceReleaseMode allows you to switch CssTransformer or JsTransformer to release mode, when it comes to debug of code by using Visual Studio debugger.

At the last stage of processing assets are a produced combination of their code. Combined code difficult to debug, because it is uncertainly where starts and ends code of a particular asset.

To facilitate debugging of combined code, you must make following changes to Web.config file:

<configuration>
   ...
   <bundleTransformer>
      <core enableTracing="true" ...>
         ...
      </core>
      ...
   </bundleTransformer>
</configuration>

If the enableTracing attribute assign a value equal to true, then on stage of combination code of each file will be wrapped in region.

Example of a region in CSS-code:

/*#region URL: /Content/Site.css */
html {
   background-color: #e2e2e2;
   margin: 0;
   padding: 0;
}
...
/*#endregion*/

Example of a region in JS-code:

//#region URL: /Scripts/AjaxLogin.js
$(function () {
   // Cache for dialogs
   var dialogs = {};
   ...
});
//#endregion

Configuration settings

Starting with version 1.2.1 Beta from the Web.config file has been removed settings of Bundle Transformer, which were default settings. Current settings of Bundle Transformer equivalent to following version of the Web.config file:  

<?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.Less.Configuration.LessSettings" />
      <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" />
	  ...
    </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">
      <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" />
        </minifiers>
        <translators>
          <add name="NullTranslator"
            type="BundleTransformer.Core.Translators.NullTranslator, BundleTransformer.Core" 
            enabled="false" />
          <add name="LessTranslator"
            type="BundleTransformer.Less.Translators.LessTranslator, BundleTransformer.Less" 
            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" />
        </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>
    </core>
    <less useNativeMinification="false"/>
    <sassAndScss useNativeMinification="false"/>
    <microsoftAjax>
      <css allowEmbeddedAspNetBlocks="false" colorNames="Strict" commentMode="Important" 
        ignoreErrorList="" indentSize="4" minifyExpressions="true" 
        outputMode="SingleLine" preprocessorDefineList="" termSemicolons="false" 
        severity="4" />
      <js allowEmbeddedAspNetBlocks="false" collapseToLiteral="true" 
        combineDuplicateLiterals="false" 
        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" preprocessorDefineList="" 
        preserveFunctionNames="false" preserveImportantComments="true" 
        removeFunctionExpressionNames="true" 
        removeUnneededCode="true" renamePairs="" strictMode="false" 
        stripDebugStatements="true" termSemicolons="false" severity="0"/>
    </microsoftAjax>
    <yui>
      <css compressionType="StockYuiCompressor" removeComments="true" 
        lineBreakPosition="-1" />
      <js compressionType="YuiStockCompression" isVerboseLogging="true" 
        isObfuscateJavascript="true" preserveAllSemicolons="false" 
        disableOptimizations="false" isEvalIgnored="false"
        lineBreakPosition="-1" />
    </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" 
          severity="0" />
      </js>
    </closure>
  </bundleTransformer>
  <!-- /Bundle Transformer configuration settings -->
  ...
</configuration>

Also since version 1.2.1 Beta in the Web.config file for the bundleTransformer configuration section was implemented support for IntelliSense:

IntelliSense support when editing the  bundleTransformer configuration section in the Web.config file

Translators

Bundle Transformer: LESS

BundleTransformer.Less contains translator-adapter LessTranslator, which produces translation of LESS-code to CSS-code by using NuGet-package the dotless.

Bundle Transformer: LESS Lite

BundleTransformer.LessLite contains translator-adapter LessTranslator, which produces translation of LESS-code to CSS-code by using NuGet-package the DotlessClientOnly.

Bundle Transformer: Sass and SCSS

BundleTransformer.SassAndScss contains translator-adapter SassAndScssTranslator, which produces translation of Sass- and SCSS-code to CSS-code by using the SassAndCoffee.Ruby.

Bundle Transformer: CoffeeScript

BundleTransformer.CoffeeScript contains translator-adapter CoffeeScriptTranslator, which produces translation of CoffeeScript-code to JS-code by using the SassAndCoffee.JavaScript.

Minifiers

Bundle Transformer: Microsoft Ajax

BundleTransformer.MicrosoftAjax contains 2 minifier-adapters: MicrosoftAjaxCssMinifier (for minification of CSS-code) and MicrosoftAjaxJsMinifier (for minification of JS-code). These adapters perform minification using the Microsoft Ajax Minifier.

To make MicrosoftAjaxCssMinifier is the default CSS-minifier and MicrosoftAjaxJsMinifier is the default JS-minifier, you need to make changes to the Web.config file. In defaultMinifier attribute of \configuration\bundleTransformer\core\css element must be set value equal to MicrosoftAjaxCssMinifier, and in same attribute of \configuration\bundleTransformer\core\js element - MicrosoftAjaxJsMinifier.

Bundle Transformer: YUI

BundleTransformer.Yui contains 2 minifier-adapters: YuiCssMinifier (for minification of CSS-code) and YuiJsMinifier (for minification of JS-code). These adapters perform minification using the YUI Compressor for .NET.

To make YuiCssMinifier is the default CSS-minifier and YuiJsMinifier is the default JS-minifier, you need to make changes to the Web.config file. In defaultMinifier attribute of \configuration\bundleTransformer\core\css element must be set value equal to YuiCssMinifier, and in same attribute of \configuration\bundleTransformer\core\js element - YuiJsMinifier.

Bundle Transformer: Closure

BundleTransformer.Closure contains 2 minifier-adapters for minification of JS-code: ClosureRemoteJsMinifier and ClosureLocalJsMinifier. ClosureRemoteJsMinifier is based on the Google Closure Compiler Service API and requires a permanent connection to Internet. ClosureLocalJsMinifier is based on the Google Closure Compiler Application and for their work requires latest version of file compiler.jar.

To make ClosureRemoteJsMinifier or ClosureLocalJsMinifier is the default JS-minifier, you need to make changes to the Web.config file. In the defaultMinifier attribute of the \configuration\bundleTransformer\core\js element must be set value equal to ClosureRemoteJsMinifier or ClosureLocalJsMinifier.

To start using ClosureLocalJsMinifier need to make the following preliminary work:

  1. On your computer must be installed Java 6 or higher. Latest version of Java can be downloaded at the following URL - http://www.java.com/download/.
  2. You need to download latest version of the Google Closure Compiler Application, which is located on the URL - http://closure-compiler.googlecode.com/files/compiler-latest.zip.
  3. Unzip the downloaded archive and copy the file compiler.jar in some directory on disk of your computer.
  4. In Web.config file find the configuration/bundleTransformer/closure/local element, then set the javaVirtualMachinePath attribute to a value equal to the path to executable file of the Java Virtual Machine (java.exe), and set the closureCompilerApplicationPath attribute to a value equal to the path to JAR-file of the Google Closure Compiler Application (compiler.jar).

Bundle Transformer: JSMin

BundleTransformer.JsMin contains one minifier-adapter for minification of JS-code - CrockfordJsMinifier. CrockfordJsMinifier is based on the C# port of Douglas Crockford's JSMin (version of May 22 2007).

To make CrockfordJsMinifier is the default JS-minifier, you need to make changes to the Web.config file. In the defaultMinifier attribute of the \configuration\bundleTransformer\core\js element must be set value equal to CrockfordJsMinifier.

Last edited Jan 24, 2015 at 11:29 AM by Taritsyn, version 8