It’s been 7 months since the last post in my YSlow series. So why did I stop blogging about performance optimization? Well actually there are two answers to that question. First on is my passion for unit-testing which I started blogging about at pretty much that time. Secondly I have to admit, that I didn’t know what to write about YSlow rule #13 – Remove Duplicate Scripts.

So what’s the problem with including the same JavaScript twice (or more)? When the browser reaches a script import it makes a HTTP request for that script. Not all browsers are smart enough to catch this mistake. Even with modern and fast internet connections, making a lot of requests, slow down the experience of your website. If you have your caching strategy under control the duplicate request shouldn’t be much of a problem but if not, the remote request is actually made multiple times. I typically see two different patterns when people by accident include the same script twice.

Pattern 1: Including scripts i both layout/master page and partial views

Partial views in ASP.NET MVC are a great way to extract common reusable controls into a single file. A partial view has the possibility to load external JavaScript files as well. A common mistake by web developers, is to include a reference to the same script in both the layout/master page-file as well as a partial view. I haven’t really found a great solution to catch this mistake, other than running YSlow on your page. If you read this and know a solution to this problem, please let me know in the comments.

Pattern 2: Including both minified and unminified version of a script

I’ve seen multiple websites doing something like this:


<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

You typically see this pattern from webdev-cowboys needing to track down some bug in the JavaScript by adding the unminified version of jQuery to be able to debug it. When the bug is fixed, they forget to remove the newly added reference. The mistake won’t show itself in the browser, because the last imported script override the first. I was a bit disapointed by the new bundling support in ASP.NET MVC 4 when I found out, that the bundler always adds the minified version if available. Making it chose the full version in Debug configuration and the minified version in Release configuration would have been the optimal choice for me.

I’m working to catch this bug in my upcoming website validator HippoValidator.com.

One of the rules mentioned in most performance-analyzing tools is “Combine your JavaScript.” Basically this means that instead of this:


<script type="text/javascript" src="/scripts/one.js></script>

<script type="text/javascript" src="/scripts/two.js></script>

<script type="text/javascript" src="/scripts/three.js></script>

<script type="text/javascript" src="/scripts/four.js></script>

<script type="text/javascript" src="/scripts/five.js></script>

You want to do this instead:


<script type="text/javascript" src="/scripts/complete.js></script>

So what’s the problem with approach number 1? When your browser parses the HTML and reaches the script tag, it makes an http request to fetch the script referenced in the src attribute. The rendering of the page blocks, until the script is loaded. Combining the five scripts into one removes the overhead of doing four http requests. The combined script will of course get the same size as the five individual scripts, but the browser only needs to do one request to get it.

You can manually combine your scripts, but this is tedious and error prone. Instead you should use a tool like SquishIt by Justin Etheredge. Justin explains the concept in great detail here. The basic idea is to keep you scripts and style sheets separate and combine them at runtime. All you need to do is download SquishIt, reference the SquishIt.Framework.dll in your project, import the SquishIt.Framework namespace in your master page, and add the following line instead of the above five script imports:

<%= Bundle.JavaScript()
.Add("/scripts/one.js")
.Add("/scripts/two.js")
.Add("/scripts/three.js")
.Add("/scripts/four.js")
.Add("/scripts/five.js")
.Render("/scripts/combined_#.js")
%>
SquishIt will generate a file name combined followed by a hash of the five files. All at runtime! It doesn’t get much better than this. We still have our scripts in separate logical files, but the clients only have to request one file. The same API is used for style sheets as well. Here you need to call the Css() method on the bundle class instead.
(Proofread by inWrite)