Skip to content

Unbundling scripts for debugging

Vitor edited this page Nov 30, 2020 · 5 revisions

During debugging it can be useful for your application to include all of the component scripts instead of the bundle. One option for this is to use an HTML Helper to generate the script elements in your view.

ASP.NET MVC5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
using System.IO;
using System.Text;

namespace MyApplication
{    
    public static class Bundler
    {
        const string FILENAME = "bundleconfig.json";

        public static MvcHtmlString RenderScripts(string bundlePath, bool? expandBundle = null)
        {
            if (expandBundle ?? HttpContext.Current.IsDebuggingEnabled)
            {
                // we're expanding the bundle so get the desired bundle configuration
                string baseFolder = HttpContext.Current.Server.MapPath("");
                var configFile = Path.Combine(baseFolder, FILENAME);
                var bundles = GetBundles(configFile);
                var bundle = (from b in bundles where b.OutputFileName.Equals(bundlePath, StringComparison.InvariantCultureIgnoreCase) select b).FirstOrDefault();
                if (bundle == null)
                    return null;

                // build script elements for each input file in the bundle
                var sb = new StringBuilder();
                var inputFiles = GetBundleInputFiles(baseFolder, bundle);
                foreach (var inFile in inputFiles)
                {
                    var fullPath = VirtualPathUtility.ToAbsolute(string.Format("~/{0}", inFile));
                    if (bundlePath.EndsWith(".css"))
                    {
                        sb.AppendLine(string.Format("<link href='{0}' rel='stylesheet'></link>", fullPath));
                    }
                    else
                    {
                        sb.AppendLine(string.Format("<script src='{0}' type='text/javascript'></script>", fullPath));
                    }
                }
                return new MvcHtmlString(sb.ToString());
            }
            else
            {
                // we're not expanding the bundle to just add as-is
                var fullPath = VirtualPathUtility.ToAbsolute(string.Format("~/{0}", bundlePath));
                if (bundlePath.EndsWith(".css"))
                {
                    return new MvcHtmlString(string.Format("<link href='{0}' rel='stylesheet'></link>", fullPath));
                }
                else
                {
                    return new MvcHtmlString(string.Format("<script src='{0}' type='text/javascript'></script>", fullPath));
                }
            }
        }


        // below is mostly copied from Mads Kristensen's BundlerMinifier -> BundleHandler.cs 
        static List<string> GetBundleInputFiles(string baseFolder, Bundle bundle)
        {
            List<string> inputFiles = new List<string>();
            string ext = Path.GetExtension(bundle.OutputFileName);
            foreach (string inFile in bundle.InputFiles)
            {
                string fullPath = Path.Combine(baseFolder, inFile);

                if (Directory.Exists(fullPath))
                {
                    DirectoryInfo dir = new DirectoryInfo(fullPath);
                    var files = dir.GetFiles("*" + ext, SearchOption.TopDirectoryOnly);
                    inputFiles.AddRange(files.Select(f => string.Format("{0}/{1}", inFile, f.Name)));
                }
                else
                {
                    inputFiles.Add(inFile);
                }
            }
            return inputFiles;
        }

        static IEnumerable<Bundle> GetBundles(string configFile)
        {
            FileInfo file = new FileInfo(configFile);

            if (!file.Exists)
                return Enumerable.Empty<Bundle>();

            string content = File.ReadAllText(configFile);
            return JsonConvert.DeserializeObject<IEnumerable<Bundle>>(content);
        }

    }
    
    class Bundle
    {
        [JsonProperty("outputFileName")]
        public string OutputFileName { get; set; }

        [JsonProperty("inputFiles")]
        public List<string> InputFiles { get; set; } = new List<string>();

        [JsonProperty("minify")]
        public Dictionary<string, object> Minify { get; set; } = new Dictionary<string, object> { { "enabled", true } };

        [JsonProperty("includeInProject")]
        public bool IncludeInProject { get; set; }

        [JsonProperty("sourceMaps")]
        public bool SourceMaps { get; set; }
    }
}

The second parameter expandBundle is optional and if omitted expanding the bundle is based on HttpContext.Current.IsDebuggingEnabled.

    @Bundler.RenderScripts("Content/myApp/bundle.js")

...or to you can make the choice yourself..

    @Bundler.RenderScripts("Content/myApp/bundle.js", true)
    @Bundler.RenderScripts("Content/myApp/bundle.js", false)

ASP.NET CORE

ASP.NET Core requires a different way to bundle, I have included a way here https://gist.github.com/mohamedmansour/cd50123f8575daba7a7f12847b12da5d

Alternatively, using UnbundleTagHelper will allow you to write

<unbundle src="~/js/site.js">

and have it expand to

<script src="/js/my_file1.js"></script>
<script src="/js/my_file2.js"></script>
Clone this wiki locally