Question

I am just trying out ASP.NET MVC 4 but I can't figure out how to disable Javascript/CSS minification feature. Especially for development environment this will help greatly on debugging. I would imagine it would be a switch in web.config but since ASP.NET MVC 4 is still in beta stage at the moment there's really not much information out there. Would appreciate if someone can help or point to the right blog posts etc.

Was it helpful?

Solution

In Global.asax.cs

#if DEBUG
        foreach (var bundle in BundleTable.Bundles)
        {
            bundle.Transform = new NoTransform();
        }
#endif

OTHER TIPS

Another option would be to create an HTML Helper that you could use to build the script and link tags. Here is what I have implemented for the Javascript, which can also be done for the CSS:

public static class BundleHelper
    {
        public static MvcHtmlString JsBundle(this HtmlHelper helper, string bundlePath)
        {
            var jsTag = new TagBuilder("script");
            jsTag.MergeAttribute("type", "text/javascript");

            return ReferenceBundle(helper, bundlePath, jsTag);
        }

        public static MvcHtmlString ReferenceBundle(this HtmlHelper helper, string bundlePath, TagBuilder baseTag)
        {
            var httpContext = helper.ViewContext.HttpContext;
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

            Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
            var htmlString = new StringBuilder();

            if (bundle != null)
            {
                var bundleContext = new BundleContext(helper.ViewContext.HttpContext, BundleTable.Bundles, urlHelper.Content(bundlePath));

                if (!httpContext.IsDebuggingEnabled)
                {
                    baseTag.MergeAttribute("href", System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(bundlePath));
                    return new MvcHtmlString(baseTag.ToString());
                }

                foreach (var file in bundle.EnumerateFiles(bundleContext))
                {
                    var basePath = httpContext.Server.MapPath("~/");
                    if (file.FullName.StartsWith(basePath))
                    {
                        var relPath = urlHelper.Content("~/" + file.FullName.Substring(basePath.Length));
                        baseTag.MergeAttribute("href", relPath, true);
                        htmlString.AppendLine(baseTag.ToString());
                    }
                }

            }

            return new MvcHtmlString(htmlString.ToString());
        }
    }

Now all that you have to do is call it in your view:

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <link href="~/Content/css" rel="stylesheet" type="text/css" />
    <link href="~/Content/themes/base/css" rel="stylesheet" type="text/css" />
    @Html.JsBundle("~/scripts/js")
    <meta name="viewport" content="width=device-width" />
</head>

And it will render the scripts as separate references, or use the new bundling/minification feature depending on what the debug setting is in your web.config . I used some of the code from http://codecutout.com/resource-minify-bundling as a reference when creating my helper if you wanted to see some more examples. Their helper is written a little better, throwing exceptions when invalid arguments are supplied, etc.... I just haven't gotten around to cleaning mine up yet.

You could register your own bundles in the Global.asax and use the NoTransform class if you do not want the content to be minified.

I personally don't want my script to be transformed at all. I just create two script directories. One with the debug script versions and one with the originally downloaded minified versions.

The MVC 4 out of the box minifier (JsMinify) breaks jQuery 1.7.1 for Opera, so I do not want to use that one. I just put the following lines in my Global.asax: Application_Start() method:

Bundle debugScripts = new Bundle("~/DebugScripts", 
    new NoTransform("text/javascript"));
debugScripts.AddDirectory("~/Scripts/Debug", "*.js");
BundleTable.Bundles.Add(debugScripts);

Bundle productionScripts = new Bundle("~/ProductionScripts", 
    new NoTransform("text/javascript"));
productionScripts.AddDirectory("~/Scripts/Minified", "*.js");
BundleTable.Bundles.Add(productionScripts);

With that in place I can simply add either one of two lines in my _layouts.cshtml:

<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/DebugScripts")" type="text/javascript"></script>
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/ProductionScripts")" type="text/javascript"></script>

Of course we could get a little more funky with this in place. We could generate just one bundle and depending on the built type select what files to include.

After the call to EnableDefaultBundles() in Global.asax, you can do this ...

        if ( ... running in development environment ...)
        {
            var registeredBundles = BundleTable.Bundles.GetRegisteredBundles();
            foreach (var bundle in registeredBundles)
            {
                if (bundle.Transform is System.Web.Optimization.JsMinify)
                    bundle.Transform = new NoTransform();
            }
        }

Not pretty (modifying state set by the system), but it's a lot less code than all the other suggestions, still lets you use the standard bundling behavior and it doesn't involve any changes to your views.

On newer versions of ASP.NET MVC just add

#if DEBUG
            foreach (var bundle in BundleTable.Bundles)
            {
                bundle.Transforms.Clear();
            }
#endif

right after

BundleConfig.RegisterBundles(...);

you can turn it off from config:

<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>

http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification

I think it would be right, if such feature will be available "out of the box".

I posted a feedback on UserVoice.com: http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/2702000-improve-system-web-optimization-bundle

Give it your "voices".

Rather than replace instances of JsMinify and CssMinify, one can instead use interfaces. This option was not available in earlier releases because the second constructor parameter was a type rather than an interface.

IBundleTransform jsTransform;
IBundleTransform cssTransform;

#if DEBUG
    jsTransform = new NoTransform("text/javascript");
    cssTransform = new NoTransform("text/css");
#else
    jsTransform = new JsMinify();
    cssTransform = new CssMinify();
#endif

Bundle jsBundle = new Bundle("~/JsB", jsTransform);
Bundle cssBundle = new Bundle("~/CssB", cssTransform);

Perhaps also worth noting, for scripts that are shipped with minified and non-minified versions e.g. jQuery, one can use a helper method to optionally strip out the ".min" for DEBUG builds to facilitate debugging:

private string Min(string scriptNameIncludingMin)
{
#if DEBUG
    return scriptNameIncludingMin.Replace(".min", ""); // Remove .min from debug builds
#else
    return scriptNameIncludingMin;
#endif
}

// ...
jsBundle.AddFile(Min("~/Scripts/jquery-1.7.2.min.js"));

Try a new extension for System.Web.Optimization - Bundle Transformer. In Bundle Transformer implemented a number of opportunities to simplify debugging (see documentation).

Another alternative (tested with v1.1.0.0 and MVC5):

public class BundleConfig
{
    public static void Register()
    {
        ScriptBundle jsBundle = new ScriptBundle("~/Scripts/myscript.min.js");
        jsBundle.Include("~/Scripts/myscript.js");
        DisableInDebugMode(jsBundle);

        BundleTable.Bundles.Add(jsBundle);
    }

    private static void DisableInDebugMode(ScriptBundle jsBundle)
    {
    #if DEBUG
        // Don't minify in debug mode
        jsBundle.Transforms.Clear();
    #endif
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top