When you want to combine and minify your JavaScript and CSS there’s a lot of options out there. Mainly you can either do this in your build process or perform this “on demand” from the server side of your website. When it comes to performance the first option, to actually deploy the processed assets, is probably the most efficient but I often prefer to take the cost of processing this on the server side using something like Microsoft.AspNet.Web.Optimization or ClientDependency Framwork (ships with Umbraco).

In this post I’ll explain the steps needed to use Microsofts Web.Optimization-framework and the 3rd party package System.Web.Optimization.Less to be able to process use .less-files on the server.

Note: The Less-package that I’m using needs at least .NET Framework 4.6.1 to run, so before going further, make sure that you’re project runs on at least .NET Framework 4.6.1.

First of, we need to install the two packages that we’re going to use:

Install-Package Microsoft.AspNet.Web.Optimization

and

Install-Package System.Web.Optimization.Less

After installing these packages we need to configure our bundle during startup. For a vanilla MVC-project this would be done in Global.asax but when we're running Umbraco we can avoid having to fiddle with Global.asax by creating our own ApplicationEventHandler (for V7) or UserComponent (for V8).

Before we configure our bundles we need to make sure that the path we're using for our bundles is ignored by Umbraco, otherwise we might get issues with 404-responses from the bundle. Make sure the root web.config contains a appSettings that looks something like this: 

<add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/bundles/"/>

 Then we can start to configure our bundle, when running Umbraco 7 it would look something like this

public class UmbracoStartup : ApplicationEventHandler
{
    protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
    {
        this.RegisterBundles(BundleTable.Bundles);
    }

    public void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/js") 
            .Include("~/Scripts/site.js")
        );

        bundles.Add(new LessBundle("~/bundles/css")
            .Include("~/Style/site.less")
        );
    }
}

 Then in your views you'll render the bundle links like this:

@Styles.Render("~/bundles/css")

After this the bundle will be rendered on the front end of the website, please note that it behaves differently depending on the system.web -> compilation -> debug setting in the root web.config:

  • Debug = true (for development): Each file in the bundle is referenced with it's own <script>-tag
  • Debug = false (for production): Files and bundles (and minified if configured).

A good practice is to test both these settings in your development environment to make sure that everything works.

A very nice feature in the latest version of Umbraco (8.0+) is that they’ve made it really easy to implement your own CollectionBuilders. This raises two obvious questions:

What is a CollectionBuilder?

A collection builder is used to create a collection of Types, the main purpose being a collection of types that you would like to keep in a certain order. Umbraco uses this to register stuff like ContentFinders, Components and lots of other things.
The syntax looks something like this:

// Append
composition.Components().Append<MyCustomComponent>()
// Insert After
composition.Components().InsertAfter<MyCustomComponent,AnotherComponent>()

By leverage this feature you can create your own collection of types and make sure that the concrete instances in the collection is sorted in the way you want.

How would I implement a custom CollectionBuilder?

We’re basically looking at 3 small pieces that we need to get this in place. Let’s say that we have a type called ITextProcessor with multiple different implementations that we need to store in our custom collection in a given order. We’ll start with the collection it self by creating a new class that inherits from BuilderCollectionBase, all we need to do is to pass the type we want to store in the collection as a type parameter and implement the default constructor: 

public class TextProcessorsCollection : BuilderCollectionBase<ITextProcessor>
{
    public TextProcessorsCollection (IEnumerable< ITextProcessor > items) : base(items)
    {
    }
}

 Next up is the “Collection Builder” it self, here we inherit from “OrderedCollectionBuilderBase” and pass 3 type parameters:
1. The builder type it self
2. The collection type
3. The type of the items in the collection


And also implement one single property, “This”. It should look something like:

public class TextProcessorsCollectionBuilder :
OrderedCollectionBuilderBase< TextProcessorsCollectionBuilder, TextProcessorsCollection,ITextProcessor>
{
    protected override TextProcessorsCollectionBuilder This => this;
}

 The last thing we should do is to implement an extension method so the builder will be easy to use during composition, let’s create one like this:

public static class TextProcessorsCollectionExtensions
{
    public static TextProcessorsCollectionBuilder TextProcessors(this Composition composition)
=> composition.WithCollectionBuilder< TextProcessorsCollectionBuilder >();
}

After this we can work with our list during Composition using the extension method like so:

public class MySiteComposer : IUserComposer
{
    public void Compose(Composition composition)
    {
    composition.TextProcessors().Append<RemoveSpaceTextProcessor>();
    composition.TextProcessors().Append<AddLineBreaksTextProcessor>();
    }
}

 When we want to use the list in our code, we can get it from the IOC-container, prefferebly using consrtructor injection

public class MyController : SurfaceController
{
    public void MyController(TextProcessorsCollection textProcessors)
    {
        // Save as local variable
    }
}