Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime dynamic bundling and minifying in MVC 4

I was wondering if anybody can help me with bundling and minifying using the new optimization namespace shipped with MVC 4. I have a Multitenant-application in which I want to decide which js files should be loaded based on settings per user. One approach would be to create all bundles upfront and change the virtual path of resolvebundleurl based on the setting of the user, but that feels not really the right way. Also I have dynamic css in a cshtml view based on user-settings, which I would like to have minified in runtime.

Any suggestions? I also see a lot of reactions in other questions to check out Requestreduce, but they are all from the same user.

What would be the best approach to handle both situations?

Thanks in advance!

like image 460
Cyril Mestrom Avatar asked May 16 '12 08:05

Cyril Mestrom


People also ask

What is minification and bundling in MVC?

Bundling and Minification are two performance improvement techniques that improves the request load time of the application. Most of the current major browsers limit the number of simultaneous connections per hostname to six. It means that at a time, all the additional requests will be queued by the browser.

What is the use of bundling and minification?

Bundling and minification are two techniques you can use in ASP.NET 4.5 to improve request load time. Bundling and minification improves load time by reducing the number of requests to the server and reducing the size of requested assets (such as CSS and JavaScript.)

What are the two types of bundles in MVC 5?

Bundle TypesScriptBundle: ScriptBundle is responsible for JavaScript minification of single or multiple script files. StyleBundle: StyleBundle is responsible for CSS minification of single or multiple style sheet files.

What is the use of Bundleconfig in MVC?

The MVC provides us the two features to reduce the number of requests to access the resource file on the server i.e. Bundling and Minification. Bundling is one of the features of MVC. By implementing this, we can improve performance request load time.


3 Answers

One approach you can take is building the bundle dynamically when the application starts. So if your scripts are located in ~/scripts you can do:

Bundle bundle = new Bundle("~/scripts/js", new JsMinify());

if (includeJquery == true) {     
  bundle.IncludeDirectory("~/scripts", "jquery-*");
  bundle.IncludeDirectory("~/scripts", "jquery-ui*");
} 

if (includeAwesomenes == true) {
  bundle.IncludeDirectory("~/scripts", "awesomeness.js");
}

BundleTable.Bundles.Add(bundle);

Then your markup can look like this

@Scripts.Render("~/Scripts/Libs/js")

Note: I'm using the latest nuget package for system.web.optimization (now Microsoft.AspNet.Web.Optimization) located here. Scott Hanselman has a good post about it.

like image 62
JaySilk84 Avatar answered Oct 12 '22 03:10

JaySilk84


i wrote a helper function to dynamic minify my css & js

    public static IHtmlString RenderStyles(this HtmlHelper helper, params string[] additionalPaths)
    {
        var page = helper.ViewDataContainer as WebPageExecutingBase;
        if (page != null && page.VirtualPath.StartsWith("~/"))
        {
            var virtualPath = "~/bundles" + page.VirtualPath.Substring(1);
            if (BundleTable.Bundles.GetBundleFor(virtualPath) == null)
            {
                var defaultPath = page.VirtualPath + ".css";
                BundleTable.Bundles.Add(new StyleBundle(virtualPath).Include(defaultPath).Include(additionalPaths));
            }
            return MvcHtmlString.Create(@"<link href=""" + HttpUtility.HtmlAttributeEncode(BundleTable.Bundles.ResolveBundleUrl(virtualPath)) + @""" rel=""stylesheet""/>");
        }
        return MvcHtmlString.Empty;
    }

    public static IHtmlString RenderScripts(this HtmlHelper helper, params string[] additionalPaths)
    {
        var page = helper.ViewDataContainer as WebPageExecutingBase;
        if (page != null && page.VirtualPath.StartsWith("~/"))
        {
            var virtualPath = "~/bundles" + page.VirtualPath.Substring(1);
            if (BundleTable.Bundles.GetBundleFor(virtualPath) == null)
            {
                var defaultPath = page.VirtualPath + ".js";
                BundleTable.Bundles.Add(new ScriptBundle(virtualPath).Include(defaultPath).Include(additionalPaths));
            }
            return MvcHtmlString.Create(@"<script src=""" + HttpUtility.HtmlAttributeEncode(BundleTable.Bundles.ResolveBundleUrl(virtualPath)) + @"""></script>");
        }
        return MvcHtmlString.Empty;
    }

usage

~/views/Home/Test1.cshtml

~/Views/Home/Test1.cshtml.css

~/Views/Home/Test1.cshtml.js

in Test1.cshtml

@model object
@{
   // init
}@{

}@section MainContent {
  {<div>@{
     if ("work" != "fun")
     {
        {<hr/>}
     }
  }</div>}
}@{

}@section Scripts {@{
  {@Html.RenderScripts()}
}@{

}@section Styles {@{
  {@Html.RenderStyles()}
}}

but ofcoz, i put most of my sripts,styles in ~/Scripts/.js, ~/Content/.css

and register them in Appp_Start

like image 44
3 revs Avatar answered Oct 12 '22 01:10

3 revs


We considered supporting dynamic bundles early on, but the fundamental issue with that approach is multi server scenarios (i.e. cloud) won't work. If all bundles are not defined in advance, any bundle requests that get sent to a different server than the one that served the page request will get 404 response(as the bundle definition would only exist on server that handled the page request). As a result, I would suggest creating all bundles up front, that's the mainline scenario. Dynamic configuration of bundles might work as well, but that is not a fully supported scenario.

like image 27
Hao Kung Avatar answered Oct 12 '22 01:10

Hao Kung