14

I've started using bundling and minification included with the MVC4 Beta. I'm running into a few issues with it:

For one thing, if I use the classic <script src="Folder/js" type="text/javascript"/> bundling, it seems like I have to rename my files to make sure they're bundled in the proper order.

  • Let's say I have three javascript files: "ants.js", "bugs.js", "insects.js"
  • ants.js depends on bugs.js
  • bugs.js depends on insects.js
  • Default bundling seems to bundle them in alphabetical order.
  • To get them to bundle properly, I have to rename them to: "0.insects.js", "1.bugs.js", "2.ants.js"
  • That's really hackish and there has to be a cleaner way.

The next problem I'm having is debugging. I like to step through the javascript in my testing browsers, is there a way to turn off just the minification while in DEBUG mode?

EDIT: To be clear, I know I can create bundles and register them from C#, it just seems really ugly to have to do it that way.

Hao Kung
  • 28,040
  • 6
  • 84
  • 93
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • Related question - http://stackoverflow.com/questions/9373071/how-to-disable-javascript-css-minification-in-asp-net-mvc-4 – resnyanskiy Mar 21 '12 at 08:30

4 Answers4

11

To temporarily get non-minified output use this

  public class NonMinifyingJavascript : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse bundle)
    {
        if(bundle == null)
        {
            throw new ArgumentNullException("bundle");
        }

        context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies();

        foreach(FileInfo file in bundle.Files)
        {
            HttpContext.Current.Response.AddFileDependency(file.FullName);
        }

        bundle.ContentType = "text/javascript";
        //base.Process(context, bundle);
    }
}

If you wanted it based totally on a config setting, I imagine you could create an IBundle transform that delegates to this one or JsMinify depending on your config setting

In order to control the ordering of the javascript files you need to use the BundleFileSetOrdering

 var javascriptBundle = new Bundle("~/site/js", new NonMinifyingJavascript());

         //controls ordering for javascript files, otherwise they are processed in order of AddFile calls
         var bootstrapOrdering = new BundleFileSetOrdering("bootstrap");
         //The popover plugin requires the tooltip plugin
         bootstrapOrdering.Files.Add("bootstrap-tooltip.js");
         bootstrapOrdering.Files.Add("bootstrap-popover.js");
         BundleTable.Bundles.FileSetOrderList.Add(bootstrapOrdering);
         javascriptBundle.AddDirectory("~/Scripts", "bootstrap-*.js");
chrisortman
  • 1,514
  • 15
  • 22
  • This does exactly what I need it to do, it sucks it can't be done a little more seemlessly, but I'll take what I can get. – Ben Lesh Mar 13 '12 at 02:38
7

I use the MVC default NoTransform instead of the NonMinifyingJavascript proposed by chrisortman. As far as I know it does the same. But still not optimal. Ideally I want a script tag for each idividual script file when I want to debug. This makes debugging a lot easier with VS11, which I like to use (one debugger so I can debug js and c# in one debug session). So I created this little helper:

@helper RenderScriptTags(string virtualPath)
{
    if (Minify /* some appsetting */)
    {
        <script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(virtualPath)"></script>
    }
    else
    {
        foreach (var file in System.Web.Optimization.BundleResolver.Current.GetBundleContents(virtualPath))
        {
            <script src="@Url.Content(file)"></script>
        }
    }
}

@RenderScriptTags("~/libraries")

I have a single page app, so I have this in my main cshtml file, but it can easily be generalized by moving this to an htmlhelper extension method. Works nice!

This code takes also into account the BundleFileSetOrdering if you have set one!

Jaap
  • 2,252
  • 2
  • 20
  • 24
2

Might also take a look at RequestReduce. It bundles your scripts and CSS without any coding or configuration by looking at how they are laid out on your page and bundling according to that. It also allows you to turn off bundling and minification via web.config or for individual requests via a querystring param: RRFilter=disabled.

Jordan Gray
  • 16,306
  • 3
  • 53
  • 69
Matt Wrock
  • 6,590
  • 29
  • 23
  • 1
    That's really interesting, and I may end up using something like that. Part of me really wants to stick with what's packaged with MVC 4, though. – Ben Lesh Mar 11 '12 at 18:48
  • 1
    If its any consolation this is what is used on alot of the MSDN/Technet properties including MSDN Blogs for bundling/minification. – Matt Wrock Mar 11 '12 at 18:54
  • Haha.. I'm glad you understood I needed consoling... because I did. I'm sort of disappointed in this new wiz-bang functionality. – Ben Lesh Mar 11 '12 at 19:51
  • RequestReduce appear to have moved from http://requestreduce.com/ to http://requestreduce.org/ – dumbledad May 10 '12 at 10:12
1

I ran into this same problem yesterday and couldn't find a good solution with the new System.Web.Optimization namespace. There were some broken MSDN links, so the fact that everything is in beta means it may change, but I digress...

You could always load the scripts differently during development than in production. Easy to do with an AppSetting:

@if (System.Configuration.
    ConfigurationManager.AppSettings["BundleResources"] != null)
{
    @* load the css & js using bundles *@
}
else
{
    @* load the css & js files individually*@
}

You can then enable / disable the optimization stuff by commenting out an appsetting in web.config:

<appSettings>
    ...
    <!--<add key="BundleResources" value="uhuh" />-->
    ...
</appSettings>
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • Yeesh, that's sub-optimal. It seems like they just made the functionality and they haven't had to use it themselves yet. I can't imagine it staying this way for long. – Ben Lesh Mar 11 '12 at 18:26
  • incidently, I was doing something similar to this with compiler directives like `@{ #if DEBUG }` it just seemed ugly. – Ben Lesh Mar 11 '12 at 18:28
  • lol, yeah I've already seen a few places where they've changed the API (new JsMinify() instead of typeof(JsMinify)). I can't imagine it will stay this way for long either. If bundling / minification is important, might also want to check out RequestReduce as Matt advertised. – danludwig Mar 11 '12 at 18:43