0

I have ASP.NET MVC application and files that are used across all CSHTML files (like jQuery, Bootstrap, Kendo JS, CSS and my own common JS file) are bundled and referenced in _Layout.cshtml.

The application have several views, partial views and most of the CSHTML have reference to their own individual JS file. How do i minify these individual files? ofcourse in debug mode i would like to use non minified file.

Should i create bundle of single file and reference it in CSHTML?
Or is there VS addon that will create minified files during development only and then in CSHTML i can do something like

#if DEBUG
 <script src="~/Areas/Users/Scripts/Users/main.js"></script>
#else
 <script src="~/Areas/Users/Scripts/Users/main.min.js"></script>
#endif

Is there any other option?

Comments: This question is not duplicate. Question is about HOW to minify single JS, it is not asking whats the Value of adding single JS.

9
  • 2
    Have you seen Bundling and minification ? Commented Dec 11, 2017 at 15:43
  • the link you provided is for .NET CORE not for classic ASP.NET Commented Dec 11, 2017 at 15:50
  • 1
    Create bundles for each page and include that in your views . Have a bundle for layout page (for all common libraries needed in all the pages). You can include the bundle virtual path and the bundle mechanism can give you non minified version when debugging locally. Commented Dec 11, 2017 at 15:52
  • 1
    @LP13 but you can create a bundle of one file. stackoverflow.com/questions/11005425/… Commented Dec 11, 2017 at 16:32
  • 1
    See Is it any value of adding one script file to BundleCollection?. Commented Dec 12, 2017 at 9:23

1 Answer 1

0

So finally i wrote my own utility.

  1. The utility registers and reference the bundles in one step in the view. (instead of registering at startup and then reference it in view).

  2. When adding single script, instead of using script's path as bundle name it dynamically creates bundle name (guid). It maps the script's path with guid and track internally in private static dictionary for reuse. For 2 reasons:

    • In my case the script's path was longer so dont want to use it as bundle name.
    • Don't want to expose script path/name to public.
  3. I can also add multiple files by specifying bundle name. ( in my case i don't see i am going to use it anywhere)

    public static class ScriptBuilder
    {
    
    private static IDictionary<string, string> _bundleNames = new Dictionary<string, string>();
    
    
    public static IHtmlString Script(string url)
    {
        var bundleName = GetBundleName(url, ".js");
        return AddScriptToBundle(bundleName, url);
    }
    
    public static IHtmlString Script(string bundleName, params string[] urls)
    {
        return AddScriptToBundle(bundleName, urls);
    }
    
    public static IHtmlString Style(string url)
    {
        var bundleName = GetBundleName(url, ".css");
        return AddStylesToBundle(bundleName, url);
    }
    
    public static IHtmlString Style(string bundleName, params string[] urls)
    {
        return AddStylesToBundle(bundleName, urls);
    }
    
    private static IHtmlString AddScriptToBundle(string bundleName, params string[] urls)
    {
        if (BundleTable.Bundles.GetBundleFor(bundleName) == null)
        {
            var thisBundle = new ScriptBundle(bundleName).Include(urls);
            BundleTable.Bundles.Add(thisBundle);
        }
        return Scripts.Render(bundleName);
    }
    
    private static IHtmlString AddStylesToBundle(string bundleName, params string[] urls)
    {
        if (BundleTable.Bundles.GetBundleFor(bundleName) == null)
        {
            var thisBundle = new StyleBundle(bundleName).Include(urls);
            BundleTable.Bundles.Add(thisBundle);
        }
        return Styles.Render(bundleName);
    }
    
    private static string GetBundleName(string url, string type)
    {
        var key = url.ToLower();
        if (!_bundleNames.ContainsKey(key))
        {
            _bundleNames[key] = "~/" + Guid.NewGuid().ToString();
        }
        return _bundleNames[key];
    }
    

    }

    Then create the HtmlHelper extension method and call this Utility inside

       public static class HtmlHelperExtensions
       {    
         public static IHtmlString Script(this HtmlHelper helper, string url)
        {
              ScriptBuilder.Script(url);
        }
    

    }

Sign up to request clarification or add additional context in comments.

5 Comments

Why don't you want to register your bundles at startup? Your code will likely be horribly inefficient. IIRC, the bundler will re-minify the file each time you create a new bundle, which would happen on every view that uses the bundle.
@am why would it create new bundle each time? its checking in the private dictionary if url exists and if does, it uses that virual path
Because you're calling the bundle's constructor each time you call your helper? Because you then call Render() for each bundle you create this way?
are we sure the bundling actually minifies the file again if the virtual path already exists? i noticed it creates the same query string value when i refresh the page.
The reason i don't want to register at startup because we have 100+ JS files and i want to create bundle for individual file. If i create bundle for individual file at starup and then reference it in the view (making sure bundle name is same) chances of typo high so instead i would prefer to automate the process in one step.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.