EPiServer CMS Site Performance Part 2: Bundling and Minifying
Next we will look at reducing the number of requests, reduce bytes on the wire, and leveraging browser caching for our EPiServer CMS site to increase performance.
Bundling and minifying JavaScript and CSS files
A good place to start to reduce the number of requests and bytes is looking at the JavaScript and CSS files we have included on every page. On our site we have 3 CSS files and 4 JavaScript files, and Google PageSpeed complains about them not being minified and having too short browser cache expiration dates set (24 hours). We can combine the CSS files into one CSS file and the JS files into one JS file, minify the combined files and set the browser cache expiration date to at least 1 year into the future.
<!--CSS--> <link rel="stylesheet" href="/css/bootstrap.css" > <link rel="stylesheet" href="/css/style.css"> <link rel="stylesheet" href="/css/CloudClinic.css"> <!--JS--> <script src="/js/jquery.js"></script> <script src="/js/jquery.mobilemenu.js"></script> <script src="/js/jquery.ui.totop.js"></script> <script src="/js/jquery.equalheights.js"></script>
There are many ways to bundle and minify files using third party tools, but as of ASP.NET 4.5 it is included in the framework, so we might as well use that. Currently a default EPiServer CMS project is set to .NET version 4.0, so the first step is to set it to .NET 4.5. Right click the project in VS and select properties. Change “Target framework” to “.NET Framework 4.5” and build your project.
To get access to the System.Web.Optimization framework we need to install a package from nuget. Open the “Packet Manager Console” and run the following line:
Install-Package Microsoft.AspNet.Web.Optimization
Now we are all set to bundle our files.
Creating the bundles
If you don’t already have an “App_Start” folder in the root of your project, create it. Create a new class in this folder named “BundleConfig.cs”. In our case we have created one bundle for our JavaScript files and one bundle for our CSS files, but you can create multiple bundles.
using System.Web.Optimization; namespace CloudClinic { public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/Bundles/JS").Include( "~/js/jquery.js", "~/js/jquery.mobilemenu.js", "~/js/jquery.ui.totop.js", "~/js/jquery.equalheights.js") ); bundles.Add(new StyleBundle("~/Bundles/CSS").Include( "~/css/bootstrap.css", "~/css/style.css", "~/css/CloudClinic.css") ); } } }
Registering our bundles
We need to register our bundles in the Global.asax.js file like this:
using System.Web.Mvc; using System.Web.Optimization; namespace CloudClinic { public class Global : EPiServer.Global { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); //Register JS and CSS bundles BundleConfig.RegisterBundles(BundleTable.Bundles); } } }
Using our bundles
Now we can swap our old CSS and JS files with the new bundles in our .cshtml file.
<!--CSS--> @Styles.Render("~/Bundles/CSS") <!--JS--> @Scripts.Render("~/Bundles/JS")
The end result
By loading the page again and viewing the source we can see the end result. (Note: If you have debug=”true” in your web.config the files won’t be bundled, so make sure to set it to false first.) The files have been bundled into just two files, they have been minified, the browser cache expiration has automatically been set to 1 year into the future and by adding a version hash query string we ensure that if we make any changes to the files the browser gets the latest version.
<!--CSS--> <link href="/Bundles/CSS?v=GSQWO59HgwIEQn34xDiBFOx9GFxcmzxP29G-QcjFvn41" rel="stylesheet"/> <!--JS--> <script src="/Bundles/JS?v=pUrWyl423vnnVLCmPyX5AF4ZNMCq1q65jNhtv0FcBL41"></script>
Bytes transferred: 326.5KB (was 333.3KB)
Requests: 30 (was 35)
Time: 1.16 seconds (was 1.27 seconds)
Go to Part 3: Optimizing images and using sprites
What happened to the minifying part? =)
Bundling, minifying and far future cache expiration is all done in one operation. :-)
So minfiying only gave you 0.6k on your js?
You only writing a and b as variable names from the start then? =)
Don't you need the BundleTable.EnableOptimizations = true;?
http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification
Of course I only user a and b as variable names. Descriptive variable names are for wusses. :-)
The reason is that jquery.js already was minified and the other 3 JS files are pretty small (5KB in total).
The minification of the CSS files however saved me 6KB.
You only need to set BundleTable.EnableOptimizations = true if you want to run the site with files bundled and debug = true.
I see, thanks for the clarification.
What about bundling conditionally? :) I cases when you need to reproduce client-side issue directly in production env..
What about bundling conditionally? :) I cases when you need to reproduce client-side issue directly in production env..
Valdis: If you need to debug javascript in production you can:
a) Set debug = true in web.config
or
b) Set BundleTable.EnableOptimizations = false in code.