23

My web app is using a large icon set with jquery-ui and jqgrid.
In order to easily maintain the changes to the CSS to accommodate the larger icons when upgrading jquery-ui or jqgrid I have a separate CSS file where I have a bunch of overrides.

As you can imagine this override file MUST be included after the jquery-ui stylesheet and the jqgrid style sheet.

I put all my stylesheets into a bundle like so

bundles.Add(new StyleBundle("~/Content/dark-hive/allstyles").Include(
    "~/Content/dark-hive/jquery-ui-1.8.23.custom.css",
    "~/Content/ui.jqgrid.css",
    "~/Content/jquery-ui-fixes.css",
    "~/Content/icons.css",
    "~/Content/site.css"));

But it is being rendered like so!

<link href="/Content/dark-hive/jquery-ui-1.8.23.custom.css" rel="stylesheet"/>
<link href="/Content/jquery-ui-fixes.css" rel="stylesheet"/>
<link href="/Content/ui.jqgrid.css" rel="stylesheet"/>
<link href="/Content/icons.css" rel="stylesheet"/>
<link href="/Content/site.css" rel="stylesheet"/>

How can I configure my bundle to render in the correct order?

Update
Ok, this is dumb but it worked.

No matter what I did the files would always render incorrectly. So I tried something stupid and added jquery-ui-fixes.css first and jquery-ui-1.8.23.custom.css last.

Suddenly my order is

<link href="/Content/jquery-ui-fixes.css" rel="stylesheet"/>
<link href="/Content/dark-hive/jquery-ui-1.8.23.custom.css" rel="stylesheet"/>
<link href="/Content/ui.jqgrid.css" rel="stylesheet"/>
<link href="/Content/icons.css" rel="stylesheet"/>
<link href="/Content/site.css" rel="stylesheet"/>

I renamed my javascript file to jqueryuifixes.css and now it's order is preserved in the lower js files.

I'm thinking that if a stylesheet has a - in the name it gets prioritized first for some reason and it's order is maintained with other files with a - in it.

If anyone can explain this I'll give them the check.

Biff MaGriff
  • 8,102
  • 9
  • 61
  • 98

2 Answers2

42

If you include each file individually, the bundle will respect your order...

var bundle = new Bundle("~/Content/dark-hive/allstyles", new StyleBundle());           
bundle.Include("~/Content/dark-hive/jquery-ui-1.8.23.custom.css");
bundle.Include("~/Content/ui.jqgrid.css");
bundle.Include("~/Content/jquery-ui-fixes.css");
bundle.Include("~/Content/icons.css");
bundle.Include("~/Content/site.css");
bundles.Add(bundle);

UPDATE

Even using explicit order, you'll find that there is a rather handy built-in ordering system that orders specifically named files first over all others. To completely clear this out, you can use:

bundles.FileSetOrderList.Clear();

And you can add your own custom ordering using:

BundleFileSetOrdering ordering = new BundleFileSetOrdering("My Order");
ordering.Files.Add("jquery.js");

bundles.FileSetOrderList.Clear();
bundles.FileSetOrderList.Add(ordering);

Essentially, there is a massive built-in list of files that will get put in a certain order before any file that isn't in the list - but these options let you take control.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 2
    The order is still incorrect, I think perhaps there is an issue with the version of the optimization dll I'm using. – Biff MaGriff Oct 30 '12 at 14:45
  • 1
    I have tested this, and there is preferential internal ordering at play, even when manually adding files in order. – Fenton Oct 30 '12 at 14:54
  • 2
    Found it - there is a big list of specific files in a certain order built in - but you can override it. Answer updated. – Fenton Oct 30 '12 at 15:02
  • Thanks for this! The automatic re-ordering of files is incredibly unintuitive. – rossisdead Jul 25 '13 at 15:15
  • This answer throws an error for me: `System.Web.Optimization.StyleBundle does not contain a constructor that takes 0 arguments The best overloaded method match for System.Web.Optimization.Bundle.Bundle(string, string) has some invalid arguments Argument 2: cannot convert from System.Web.Optimization.StyleBundle to string` – TomSelleck Feb 16 '15 at 12:17
  • We would need to see your code to reproduce - it is normally easier to ask a new question as comments are a little limited. – Fenton Feb 16 '15 at 12:19
  • @SteveFenton and how to use the updated one in the view. Thanks. – Zaker Jul 14 '15 at 09:37
  • So what's the constraint here is to add each file individually? Because it does not work when using placeholders like * – Legends Jun 18 '16 at 01:20
  • It is clearing the FileSetOrderList that fixes this issue - including each file individually as described in the answer is a red herring. – TallGuy Sep 05 '17 at 22:48
10

You can create your custom bundler and override OrderFiles method

public class CustomBundleOrderer : IBundleOrderer
{
    public IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

then pass your css files in the order you would like them to be bundled

var bundle = new StyleBundle("~/Content/dark-hive/allstyles")
{
    Orderer = new CustomBundleOrderer()
};

bundle.Include(
    "~/Content/dark-hive/jquery-ui-1.8.23.custom.css",
    "~/Content/ui.jqgrid.css",
    "~/Content/jquery-ui-fixes.css",
    "~/Content/icons.css",
    "~/Content/site.css");

bundles.Add(bundle);
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
  • 1
    The signature has changed for IBundleOrderer. public IEnumerable OrderFiles(BundleContext context, IEnumerable files) { return files; } – duyn9uyen Apr 07 '15 at 17:19