Before launching a new website, there’s a checklist I go through, to make sure that everything is ready. One of the items in my checklist is to test the website against WebPagetest.
WebPagetest is a tool that was originally developed by AOL for use internally and was open-sourced in 2008 under a BSD license. The online version at www.webpagetest.org is run for the benefit of the performance community with several companies and individuals providing the testing infrastructure around the globe.
This tool tests any website against 6 major performance affecting factors, and provides a myriad of graphs and logs that make abundantly clear what might be slowing down your site.
In this post I’ll provide ways to make your site get straight A’s in WebPagetest.
To start this off, let’s setup our environment. We’ll just need the following:
- Visual Studio 2017
- Microsoft Azure account
In Visual Studio, let’s create a new empty ASP.NET Web Application project. Then, we’ll need the latest and greatest Umbraco NuGet package (I used version 7.12.4). Once it finishes installing, just launch the website and install Umbraco with all defaults. This will bootstrap Umbraco with the Starter Website, which we’ll use as our “guinea pig” for WebPagetest.
Next: publish it! We can use the publish wizard to automatically create our new WebApp and SQL Database in Azure. Before installing Umbraco in Azure, we’ll need to change the Web.config so that the install wizard is run again (I use Filezilla to change it in Azure):
Clear the Umbraco version number:
<add key="umbracoConfigurationStatus" value="" />
Clear the Umbraco connection string:
<add name="umbracoDbDSN" connectionString="" providerName="System.Data.SqlClient" />
With this changes in place, we’re good to go. This time, we’ll not use the defaults in the Umbraco install wizard, since we’ll want to use the SQL Database we’ve just created in Azure.
For our tests, we’ll use the people page of the Starter Website. This is the score I got with a standard (S0) database and a basic WebApp:
Since this is a very small site, only used for demonstration purposes, half of the metrics are already cleared! However, this is not usually the case for bigger websites. For this reason, I’ll still present some solutions to improve the grade for these metrics.
This test measures the time it takes for the first byte to reach the client’s browser after the initial http request.
There are two main factors that influence this result:
- Server power
- The webpage complexity (integrations with external services, complex logic involved, etc)
The easiest way to mitigate this problem is by caching. You can see how to do output caching in Umbraco by reading this old post of mine: https://blogit.create.pt/andresantos/2016/06/30/umbraco-and-donut-output-cache/.
Keep alive is a method to allow the same tcp connection for HTTP conversation instead of opening a new one with each new request.
This setting is active by default in IIS, so, it’s also active by default in Azure WebApps, so it’s easy to get an A!
Just add this setting to your Web.config file:
Image compression is minimizing the size in bytes of a graphics file without degrading the quality of the image to an unacceptable level.
In Umbraco, to get an A in this grade, you need to do two things:
- Crop every image and use srcsets where you can
- Use the PostProcessor plugin for Image Processor
Cropping an image is easy in Umbraco:
<div class="employee-grid\_\_item\_\_image" style="background-image: url('@person.Photo.GetCropUrl(width: 323, height: 300, quality: 85)')"></div>
In order to use the PostProcessor plugin, you just need to install it via nuget: https://www.nuget.org/packages/ImageProcessor.Web.PostProcessor/184.108.40.206.
Static content is content that changes rarely. For this reason it can be cached in the user’s browser to avoid downloading the same file over and over again.
Just set the time it takes for the content to expire in the user’s browser and add extra mime types if you want:
<staticContent> <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.24:00:00" /> <remove fileExtension=".air" /> <mimeMap fileExtension=".air" mimeType="application/vnd.adobe.air-application-installer-package+zip" /> <remove fileExtension=".svg" /> <mimeMap fileExtension=".svg" mimeType="image/svg+xml" /> <remove fileExtension=".woff" /> <mimeMap fileExtension=".woff" mimeType="application/x-font-woff" /> <remove fileExtension=".woff2" /> <mimeMap fileExtension=".woff2" mimeType="application/x-font-woff2" /> <remove fileExtension=".less" /> <mimeMap fileExtension=".less" mimeType="text/css" /> <remove fileExtension=".mp4" /> <mimeMap fileExtension=".mp4" mimeType="video/mp4" /> <remove fileExtension=".json" /> <mimeMap fileExtension=".json" mimeType="application/json" /> </staticContent>
In Umbraco, you can achieve this last grade by doing two things:
- Use an Azure Blob Storage for media storage by installing this nuget package: https://github.com/JimBobSquarePants/UmbracoFileSystemProviders.Azure.
- Create an Azure CDN for serving this blobs through a content delivery network.
After creating an Azure CDN service and waiting about an hour for it to be available, the following presents my configuration for the media assets to be provided by it:
<?xml version="1.0" encoding="utf-8"?> <security> <services> <service name="LocalFileImageService" type="ImageProcessor.Web.Services.LocalFileImageService, ImageProcessor.Web"/> <!--Disable the LocalFileImageService and enable this one when using virtual paths. --> <service prefix="media/" name="CloudImageService" type="ImageProcessor.Web.Services.CloudImageService, ImageProcessor.Web"> <settings> <setting key="Container" value="media"/> <setting key="MaxBytes" value="8194304"/> <setting key="Timeout" value="30000"/> <setting key="Host" value="https://<umbracositename>.blob.core.windows.net/media"/> </settings> </service> </services> </security>
<?xml version="1.0" encoding="utf-8"?> <caching currentCache="AzureBlobCache"> <caches> <cache name="AzureBlobCache" type="ImageProcessor.Web.Plugins.AzureBlobCache.AzureBlobCache, ImageProcessor.Web.Plugins.AzureBlobCache" maxDays="365"> <settings> <setting key="CachedStorageAccount" value="DefaultEndpointsProtocol=https;AccountName=<accountname>;AccountKey=<accountkey>;EndpointSuffix=core.windows.net" /> <setting key="CachedBlobContainer" value="cache" /> <setting key="UseCachedContainerInUrl" value="false" /> <setting key="SourceStorageAccount" value="DefaultEndpointsProtocol=https;AccountName=<accountname>;AccountKey=<accountkey>;EndpointSuffix=core.windows.net" /> <setting key="SourceBlobContainer" value="media" /> <setting key="StreamCachedImage" value="false" /> <setting key="CachedCDNRoot" value="https://<cdnrootname>.azureedge.net" /> <setting key="CachedCDNTimeout" value="1000" /> </settings> </cache> </caches> </caching>
So, if you followed this tips correctly, you’ll be able to run WebPagetest and get the same result as I did:
You can find the complete report here: https://www.webpagetest.org/result/181127_2A_bea6941dcd20d38ab54c29409fca9363/.