21

Running my MVC4 app in debug mode (so no minification of css/scripts) works fine. As soon as I run without debug (css/scripts minified), my Twitter Bootstrap icons do not get displayed. Another thread on here suggested using bundles.IgnoreList.Clear(). But that does not seem to work for me. My BundleConfig.RegisterBundles(...) looks like this:

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.IgnoreList.Clear();

    // Some JavaScript bundles only
    // ...

    bundles.Add(new StyleBundle("~/bundles/maincss").Include(
        "~/Content/bootstrap.css",
        "~/Content/bootstrap-responsive.css",
       "~/Content/my.css"));
    }
}

All packages were installed using Nuget (as I say, it works fine in debug mode). My Content folder also contains the minified versions of both the bootstrap...css files, but not a minified version of my.css. The glyph icons are in the images sub-folder.

My _Layout.cshtml looks like this:

<head>
    ...
    @Styles.Render("~/bundles/maincss")
</head>

I should add, that by "non-debug" mode, I mean setting the debug="false" option in the Web.config file:

<compilation debug="false" targetFramework="4.5" />

Does anyone have any idea why the twitter bootstrap icons do not show in "non-debug" mode?

Thanks Rob

Rob L
  • 2,124
  • 3
  • 22
  • 50

2 Answers2

39

I'm on mobile so my apologies for brief response but I'll update later.

Read this

Long story short it had to do with relative path being fouled after bundling. But the good news is the latest bundle library resolves it.

Update

To fill in the blanks, essentially what's happening is that the CSS files have relative paths to resources (in this case an icon sprite). When in debug mode, the files are output separately to the page so the references are retained (/Content/bootstrap.css with a reference to images/glyphicons-halflings.png (making the full path /Content/images/glyphicons-halflings.png). However, when debug is removed the files are bundled and the path is now relative to whatever virtual path you gave your bundle. In the case of above, you now originate from /bundles/maincss which makes for an erroneous /bundles/maincss/images/glyphicons-halflings.png path.

The good news is that this was a resolved bug and as of Microsoft.AspNet.Web.Optimization v1.1.0 you now have CssRewriteUrlTransform that will replace all relative paths (within the CSS files) with their absolute-pathed counterpart. This means that no matter what you call the bundle, the resources will still be resolved.

So, to fix the issue, you can simple do the following:

IItemTransform cssFixer = new CssRewriteUrlTransform();

bundles.Add(
    new StyleBundle("~/bundles/maincss")
        .Include("~/Content/bootstrap.css", cssFixer)
        .Include("~/Content/bootstrap-responsive.css", cssFixer)
        .Include("~/Content/my.css", cssFixer)
);

My only qualm is how ugly this looks when you want multiple files, so to solve this you can simplify it with an extension method:

/// <summary>
/// Includes the specified <paramref name="virtualPaths"/> within the bundle and attached the
/// <see cref="System.Web.Optimization.CssRewriteUrlTransform"/> item transformer to each item
/// automatically.
/// </summary>
/// <param name="bundle">The bundle.</param>
/// <param name="virtualPaths">The virtual paths.</param>
/// <returns>Bundle.</returns>
/// <exception cref="System.ArgumentException">Only available to StyleBundle;bundle</exception>
/// <exception cref="System.ArgumentNullException">virtualPaths;Cannot be null or empty</exception>
public static Bundle IncludeWithCssRewriteTransform(this Bundle bundle, params String[] virtualPaths)
{
    if (!(bundle is StyleBundle))
    {
        throw new ArgumentException("Only available to StyleBundle", "bundle");
    }
    if (virtualPaths == null || virtualPaths.Length == 0)
    {
        throw new ArgumentNullException("virtualPaths", "Cannot be null or empty");
    }
    IItemTransform itemTransform = new CssRewriteUrlTransform();
    foreach (String virtualPath in virtualPaths)
    {
        if (!String.IsNullOrWhiteSpace(virtualPath))
        {
            bundle.Include(virtualPath, itemTransform);
        }
    }
    return bundle;
}

Which makes the above code a little cleaner. (Arguably I picked a long method name, but I like to keep the method names clear with regards to purpose)

bundles.Add(
    new StyleBundle("~/bundles/maincss").IncludeWithCssRewriteTransform(
        "~/Content/bootstrap.css",
        "~/Content/bootstrap-responsive.css",
        "~/Content/my.css"
    )
);
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • 1
    Thank you for that link, it helped me solve my issue. I changed my code as follows: bundles.Add(new StyleBundle("~/Content/maincss").Include( "~/Content/bootstrap.css", "~/Content/bootstrap-responsive.css", "~/Content/my.css")); and also removed the IgnoreList.Clear(). It works fine now. – Rob L Jul 27 '13 at 01:12
  • @RobL: no need to change bundle name, just have to use `CssRewriteUrlTransform`. I've updated my answer now that I'm on a laptop with a better keyboard. ;-) – Brad Christie Jul 27 '13 at 15:05
  • 1
    @BradChristie Apologies for reviving an old thread and for my lack of knowledge on this regard. Is there a specific reason why you chose to extend Bundle then validate that it is of type StyleBundle instead of merely extending the class StyleBundle? – Colin Banbury May 27 '14 at 09:52
  • 1
    @colin: to make it work fluently with the existing `.Include` method. Otherwise it only works when used solely. – Brad Christie May 30 '14 at 16:12
10

I ran into the same thing using Bootstrap 3.0. @brad-christie's answer solved my problem until I used NuGet to upgrade to Microsoft ASP.Net Web optimisation Framework 1.1.1. This seemed to stop the CssRewriteUrlTransform fix from working. I solved the problem by removing the references to CssRewriteUrlTransform and by creating a style sheet, bootstrap-bundle-font-fix.css, containing just the following:

@font-face {
  font-family: 'Glyphicons Halflings';
  src: url('../../Content/fonts/glyphicons-halflings-regular.eot');
  src: url('../../Content/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), 
       url('../../Content/fonts/glyphicons-halflings-regular.woff') format('woff'),
       url('../../Content/fonts/glyphicons-halflings-regular.ttf') format('truetype'), 
       url('../../Content/fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg');
}

And then including it in my bootstrap css bundle:

bundles.Add(new StyleBundle("~/bundles/Content/bootstrap")
    .Include("~/Content/bootstrap/bootstrap.css")
    .Include("~/Content/bootstrap/bootstrap-theme.css")
    .Include("~/Content/bootstrap-bundle-font-fix.css")
    .Include("~/Content/sticky-footer-navbar.css"));
Community
  • 1
  • 1
daveb
  • 386
  • 5
  • 8
  • I'm seeing a similar issue. I've got Microsoft.AspNet.Web.Optimization 1.1.3 from NuGet and it doesn't seem to be transforming relative image paths. What's going on? Did someone break CssRewriteUrlTransform? – Michael12345 Feb 28 '14 at 20:54
  • 5
    Success! I missed two things. 1) if the *.min.css is present, bundling uses that WITHOUT transforming any of the contained urls. 2) Once I remove the *.min.css file, it was transforming but mussing up the path due to a virtual folder. Resolved by following this question: http://stackoverflow.com/questions/19765238/cssrewriteurltransform-with-or-without-virtual-directory – Michael12345 Feb 28 '14 at 21:38
  • Thanks for the solution there Michael, I was experiencing the same thing – John Mc Apr 29 '14 at 22:21