Back to the drawing board...

Microsoft recently announced the official release of Visual Studio 2015. It’s faster and offers some nice new features like the Roslyn API for Intellisense and refactorings, ES2015 syntax support, and (most importantly) finally reverts those ALL CAPS MENUS back to Title Casing.

However, you may notice another change if you’ve been using Web Essentials to transpile Less to CSS in Visual Studio 2013. One of the first things you may notice about Visual Studio 2015 is that Web Essentials 2015 has dropped that feature entirely.

That leaves you in an interesting predicament after upgrading to Visual Studio 2015. The official line is that you should update your project to use the new Task Runner Explorer along with grunt or gulp for tasks like Less compilation and CSS minification. That’s a bit of a speed bump though.

I’m a proponent of using task runners like grunt and gulp (In fact, I’ve been using grunt to build this site’s client-side assets for years), but it doesn’t make sense to invest in converting all of my existing projects over to the new paradigm immediately. That’s especially true of client projects, where I can’t move an entire team to a new toolchain and workflow overnight.

However, after using Visual Studio 2015 daily for several months, I would be an unhappy camper if I could only use Visual Studio 2013 and Web Essentials 2013 to maintain those existing projects.

So, in this post I want to show you the solution I’m using to keep Less compilation working in those existing projects, without Web Essentials or any other plugins.

Why is this happening?

Finding that an upgrade from Visual Studio 2013 to 2015 breaks Less compilation is a painful realization. Since a site’s CSS is crucial and constantly changing, any breakdown in the pipeline between your keyboard and what the web server ultimately sends to browsers grabs your attention very quickly.

As it turns out, there are at least a couple good reasons why complicated features like Less compilation are being removed from Web Essentials.

  • Maintaining a sandboxed Node.js environment, inside a plugin, inside Visual Studio, was apparently just about as precarious as it sounds. In one talk, Mads shared that Microsoft’s telemetry data on what causes Visual Studio crashes/exceptions often ranked Web Essentials as the most common monthly offender, and that was largely due to Node-driven features like Less compilation and JavaScript minification. Whoops.
  • In the long run, pushing a migration toward gulp (and/or grunt) makes good sense. Replacing proprietary compilation tooling with the canonical implementation of the Less compiler is the best way to go. It reminds me a lot of Microsoft’s move to refocus from MicrosoftAjax.js to embracing jQuery back in 2008.

I’d have preferred a more gradual deprecation instead of abrupt removal, but I think this change in Web Essentials does make sense. Luckily, these transpilation features are easy to replace.

In the time since I began writing this post, Mads released a standalone extension to handle compiling Less similar to how Web Essentials did prior to the 2015 release. If you prefer an IDE plugin to generate static files, that’s a fine option.

During the interim between when I began using VS2015 and when Mads released the new plugin, I found that I prefered not relying on an extension for this task. So, I wanted to finish this post anyway, to show you this alternative and let you decide which you like best.

Enter BundleTransformer

Rather than use an extension to Visual Studio or retrofit projects with a full grunt/gulp workflow, the solution I’ve been using for a few months now starts with a project called BundleTransformer.

From the BundleTransformer project page on CodePlex:

Bundle Transformer – a modular extension for System.Web.Optimization (also known as the Microsoft ASP.NET Web Optimization Framework). Classes StyleTransformer and ScriptTransformer, included in the core of Bundle Transformer and implement interface IBundleTransform. They are intended to replace the standard classes CssMinify and JsMinify.

Essentially, BundleTransformer takes ASP.NET’s built-in Web Optimization framework and puts it on steroids. Using an assortment of packages made to work with BundleTransformer, you can use it to replace all of the compilation features in Web Essentials 2013.

Installing BundleTransformer

Installing the various NuGet packages necessary to enable BundleTransformer’s Less compilation and CSS minification features can seem intimidating at first, but the process is relatively simple if you know exactly what you need.

BundleTransformer.Core – We start with BundleTransformer’s base functionality. Everything else builds on this, so you’ll need it for the Less compilation and minification modules to work.

BundleTransformer.Less – This package gives you the option of augmenting BundleTransformer’s StyleBundles with a Less Transform. This is the key piece of functionality that we’ve been after.

BundleTransformer.MicrosoftAjax, AjaxMin – A side effect of switching over to BundleTransformer for Less compilation is that we’ll lose the Web Optimization framework’s automatic minification in release mode. Without adding something into the BundleTransformer pipeline to replace that, our compiled Less would come through without any minification in production.

There are a variety of options, but I recommend the Microsoft’s AjaxMin JavaScript/CSS minifier. There are BundleTransformer packages for more mainstream alternatives, like CleanCss, but I’ve found AjaxMin to be more reliable when deploying to a range of hosting environments. Most of the other alternatives depend on either the IE11 “ChakraRT” version of IE’s scripting engine to be available on your server (notably, ChakraRT isn’t currently available on Azure Web Apps) or require that you deploy the V8 JavaScript engine along with your project.

JavaScriptEngineSwitcher.Core, JavaScriptEngineSwitcher.Msie, MsieJavaScriptEngine – Since the Less transpiler is written in JavaScript, BundleTransformer will need access to a JavaScript engine in order to compile your LESS files. These three packages work together to provide that, making use of the underlying JavaScript engine that’s available on most any Windows or Windows Server machine (including the machines that host Azure Web Apps).

That seems like a lot to install, but you can get it all added quickly by installing these three packages and letting NuGet pull the others in as dependencies:

Of course, you can use the NuGet GUI in Visual Studio to search for and install those same three packages instead, if you prefer that over the command line. The result will be the same.

Configuring BundleTransformer for Less transpilation

Configuring BundleTransformer’s web.config sections can be challenging. Getting several of its components configured and working almost always requires a bit of confusing trial and error in my experience.

However, you can configure this one time and probably never need to think about it again. To me, this is very appealing compared with migrating a team to a new Visual Studio plugin or starting from scratch with a command line task runner.

Even better, you can copy/paste my BundleTransformer configuration for Less and AjaxMin into your web.config and be done with it even quicker:

Be sure not to skip adding that handler to system.webServer. It sets up an HttpHandler that is integral to the development experience when your site is in debug mode.

Using BundleTransformer in your site

Once you have BundleTransformer installed and configured, using it to transpile your Less files on the fly at runtime is almost as simple as using the default Web Optimization CSS bundling features.

For example,  if you had a ~/css/base.less Less file that you wanted to make available as a compiled CSS bundle at the virtual path ~/bundles/css/site:

Then, you can include that transpiled bundle on any of your Razor views just like you would any other Web Optimization bundle:

In debug mode, @Styles.Render will be replaced with individual style elements for each Less file, which is great for debugging and removes the need for sourcemaps. In production, it will be replaced with a single, optimized CSS include with everything bundled up and minified.

Defining bundles with a more fluent syntax

If you prefer the fluent syntax used in the new project template, you can almost replicate it like this:

Personally, I like this better. Both are equivalent though, except that adding the GetBundleFor probably adds a slight bit of overhead at startup when these bundles are initially built and cached.

Bundling an entire folder of Less

Personally, when I’m working with the Web Optimization bundles, I like to include a base Less file and then include the rest of the Less files in that directory afterward. That way, all of your individual CSS files are included separately in debug mode and you don’t have to worry about dealing with source maps during development.

This way, you can control inclusion order for the files that matter without needing to explicitly include every single file or resort to hacky file naming tricks.

A temporary solution?

I want to emphasize that this may not be a long-term solution for everyone. If you plan to modernize your site to run on ASP.NET 5 and MVC 6, or if you want to keep your workflow up to date with the latest and greatest, there are a few reasons why you shouldn’t apply this stopgap fix and call it quits:

  • Using platform/framework-agnostic tools, like bower, gulp, and grunt, means that you’ll have immediate access to the latest front-end development innovations and bug fixes instead of waiting for an extension update. Moving away from framework-specific extensions and packages makes it easier for you to use the current best of breed front-end tooling in your projects.
  • Visual Studio 2015 has good support for configuring and managing grunt/gulp tasks and bower/npm packages. Though you’ll still want to learn how the underlying tools work together and how their config files are structured, using these new tools with Visual Studio 2015 doesn’t necessarily mean you have to spend a lot of time at the command line if you don’t want to.
  • Further, the Web Optimization bundles that I’ll show you how to use in the next section are currently not slated for inclusion in ASP.NET 5. There’s an interesting open source replacement, but removal from the core web stack may further encourage you to move to a grunt or gulp based workflow.

For those reasons, I think it makes sense for every ASP.NET developer to eventually invest in moving to a dedicated task runner like grunt or gulp for new projects. That time investment is absolutely going to be worth the effort in the long run. Especially when the time comes to start building new projects on ASP.NET 5.

Conclusion

I hope you find this alternative as useful as I have.

As I’ve used this approach more and more, I’ve found that I really like treating my Less as source code and the generated CSS as something like a build artifact that I don’t get very involved with. Even on this site that is built with npm, grunt, and bower, my source control repository only contains Less files.

It does feel vaguely inefficient to push this work down to run time. However, the result of that work is cached in-memory after the first request to each bundle, so there really isn’t a very significant impact in practice. Running through the ASP.NET pipeline and relaying the content from cache does incur a tiny performance penalty, but that overhead is negligible for all but the most heavily trafficked sites.

What do you think? Is this something you’d use? Did I miss anything? Do you still prefer an extension like Web Compiler? Are you going full-blown grunt/gulp in Visual Studio 2015 immediately instead?