MVC bundling and minification: a BetterStyleBundle

After using MVC bundling and minification for a bit I run into a few problems. All of them are well known and will cause you trouble.

First of the problems I encountered – reordering of files in the bundle. When I add to bundle Main.css and then add MainOverrides.css I bloody-well mean it to stay in this order, cause overrides will not do anything if they are posted before the main file. Same goes to jquery and plugins.

Another issue I run into was image urls inside of css. When css files are bundled, they are output as:

<link href="/bundles/jquery-ui_css?v=U5E9COcCYIcH9HU1Qr9aiQotqSzLGT8YYDi6qhOpObk1" rel="stylesheet"/>

and relative path for the images inside of css becomes broken, because there is no folder called /bundles/jquery-ui_css/images. The solution to that would be to add new CssRewriteUrlTransform() to every css file. Anything more than 5 css files that requires this modification is becoming boring to type. So I came up with a better css bundle:

public class BetterStyleBundle : StyleBundle
{
    public override IBundleOrderer Orderer
    {
        get
        {
            return new NonOrderingBundleOrderer();
        }
        set
        {
            throw new Exception("Unable to override Non-Ordred bundler");
        }
    }

    public BetterStyleBundle(string virtualPath)
        : base(virtualPath)
    {
    }


    public BetterStyleBundle(string virtualPath, string cdnPath)
        : base(virtualPath, cdnPath)
    {
    }


    public override Bundle Include(params string[] virtualPaths)
    {
        foreach (var virtualPath in virtualPaths)
        {
            base.Include(virtualPath, new CssRewriteUrlTransform());
        }
        return this;
    }
}

// This provides files in the same order as they have been added. 
public class NonOrderingBundleOrderer : IBundleOrderer
{
    public IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
    {
        return files;
    }
}

So now you can do this:

        bundles.Add(new BetterStyleBundle("~/bundles/jquery-ui_css").Include(
            "~/Content/themes/ui-lightness/jquery-ui.css", 
            "~/Content/themes/ui-lightness/jquery.ui.theme.css",
            "~/Content/jquery-ui.overrides.css"));

And order of css files added will be preserved, along with url paths in css files.

Please note, this works in MVC5, but I did not check if the same overrides are available in MVC4.