1 Comments

So you are building a website using static .html files instead of any server side technologies such as ASP.NET. That’s cool for various reasons, but my favorite is that it allows any developer on any platform to easily contribute on GitHub. No server-side components needed. Great!

You’re almost done and decide to run performance analytics tool such as Google Page Speed on your site. Now the problems begin. Here’s some of the items that you are told to optimize:

  • Minify HTML
  • Set far-future expiration dates on static resources (JS, CSS, images etc.)
  • Use cookieless domains for static files
  • Use a CDN

You could set up build processes using Grunt to do all of this work, but it is not that simple to do – especially after you already built your website. Most of these tools require you to setup your project in a specific way from the beginning.

When you think about it, none of the above mentioned performance issues are relevant on a developer machine, they are only applicable to the live running production website. So if we could let the production server do some tricks for us to make all of this easier and without us having to modify our source code, that would be great.

StaticWebHelper

While building SchemaStore.org I encountered exactly these issues and decided to create a generic and reusable solution. My idea was to let IIS handle the issues while the website could still run statically without IIS at all on a development machine.

The StaticWebHelper NuGet package does exactly that. Here’s what it does:

  1. Minifies any .html file at runtime and output caches
  2. Fingerprints references to static resources
  3. Creates a URL rewrite rule for handling the fingerprints
  4. Set’s far future expiration dates in the web.config
  5. Has support for CDNs using an appSetting

Fingerprinting is a browser cache busting technique for changing the URL to references files, so the browsers will load any changes while still featuring far-future expiration dates. Read more about fingerprinting.

#1 and #2 happens at runtime, but only once.

 <handlers>
   <add name="FingerPrint" verb="GET" path="*.html" type="StaticWebHelper.FingerPrintHandler" />
 </handlers>
It output caches the results so that no additional files are being created on disk and you get performance similar to static file serving. Any time a referenced JS, CSS or image file is updated on disk, it generates new fingerprints automatically. It also handles conditional GET requests (status 304).

#3, #4 and #5 are all handled in the web.config.

<add key="cdnPath" value="http://schemastore.org.m82.be/" />
<add key="minify" value="true" />

I use a custom reverse proxy CDN with nodes in both Europe and North America for serving static files cookieless. If you don’t need a CDN, it is still a good idea to use a different subdomain to handle static resources such as s.mydomain.com. StaticWebHelper supports both scenarios equally and it’s easy to setup in web.config.

For fingerprinting to work, it adds a URL rewrite rule in web.config.

<rule name="FingerPrint" stopProcessing="true">
  <match url="(.+)(\.[0-9]{18})\.([a-z]{2,4})$" />
  <action type="Rewrite" url="{R:1}.{R:3}" />
</rule>

To see this in action, check out the source code of SchemaStore.org on GitHub. Especially, take a look in the web.config file.

Azure Site Extensions

If your website is hosted on Azure, then it’s really easy to let an automated Site Extension do further optimizations such as image optimization and JS/CSS minification. Read more about that here.

16 Comments

I’m a huge fan of Visual Studio extensions – both consuming and creating them. Whenever I come across a missing feature in Visual Studio, my first instinct is to search for an extension that provides it. If it doesn’t exist, I create it.

In the past couple of months, I’ve created 3 tiny extensions that each adds features I’ve been missing. Each of these are highly specialized and solves a single problem each.

Trailing Whitespace Visualizer

I like my code files clean and without unneeded trailing whitespace. Format Document (ctrl+k, ctrl+d) takes care of removing the trailing whitespace, but I’d like to see it clearly in the editor while coding. Here’s what it  looks like:

whitespace

The color can be customized in case you don’t like red.

image

Download Trailing Whitespace Visualizer on the VS Gallery

Error Watcher

I don’t normally have the Error List visible in Visual Studio, so I often save files containing errors, just to find out that my project won’t build or work at runtime. That’s annoying. I wanted a more visual way to be informed about errors without looking at the details in the Error List. My solution was to show the number of errors on the file containing them at the top of the editor window.

errorlist

When no errors exist in the file, nothing will be shown in the editor. If you save the document with errors, a small red line will flash briefly to make you aware of it.

Download Error Watcher on the VS Gallery

Add empty file

Often times I just want to add an empty file to my project. It could be a .json or .js file for instance. In cases like that, I find that going into the Add New Item dialog takes to long and I sometimes have to search for the file type I want. It would be easier if I could just enter the file name with the extension I want and have it created for me. Also, the Add New Item dialog doesn’t allow me to create file names starting with a dot like in .gitignore.

I added a button to the Add flyout context menu:

menu

This will prompt me for a file name:

prompt

Here I can type whatever file name I want and it will be created, added to my project and opened in the editor.

Download Add Empty File on the VS Gallery

Remember, unlike some browsers, Visual Studio doesn’t slow down when using multiple extensions. Most of them only load in specific circumstances and doesn’t do anything when not used. That’s true for these three extensions too.

All three extensions are of course open source on GitHub.

5 Comments

HTML5 and CSS3 introduces some new file types that enables us to create even better websites. We are now able to embed video, audio and custom fonts natively to any web page. Some of these file types are relatively new and not supported by the IIS web server by default. It’s file types like .m4v, .webm and .woff.

When a request is made to the IIS for these unsupported file types, we are met with the following error message:

HTTP Error 404.3 - Not Found

The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.

The problem is that the IIS doesn’t know how to serve these new files unless we tell it how. This can be easily done in the web.config’s <system.webServer> section by adding the following snippet:

<staticContent>
    <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
    <mimeMap fileExtension=".m4v" mimeType="video/m4v" />
    <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
    <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
    <mimeMap fileExtension=".webm" mimeType="video/webm" />

    <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
    <mimeMap fileExtension=".spx" mimeType="audio/ogg" />

    <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
    <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />

    <remove fileExtension=".eot" />
    <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
    <mimeMap fileExtension=".otf" mimeType="font/otf" />
    <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
</staticContent>

The above snippet includes support for most video, audio and font file types used by HTML5 and CSS3.

7 Comments

Last time we took a look at the performance impact of using tabs vs. spaces in HTML files. One question that arose was whether or not it’s worthwhile to minify HTML when also using GZip. Let’s run the experiment.

I’ve collected a few real-world HTML files and done some minification and GZipping on them. Here’s the result:

WebsiteFile sizeMinifiedGzipGZip & minifiedSavings
amazon.com218,642197,03253,79349,0089%
cnn.com130,014121,53427,11425,3926%
twitter.com53,46546,60812,26211,4167%
xbox.com38,88824,1398,0756,79516%

These pages already do minification on various sections, but none of them minifies the whole document. If none of them used any minification, the savings would have been higher than the table shows.

So, according to the results, minification will provide an additional 6-16% lower file size with GZip enabled.

16% is a rather large saving on top of regular GZip, so the data suggests that we must use both GZip AND minification.

Remember, this is a rather small experiment with only 4 real-world websites. It would be interesting to expand the experiment for more accurate statistics.

For HTML minification in ASP.NET, I like to use WebMarkupMin or Meleze.Web.

7 Comments

Are you using tabs or spaces to indent your markup? Does it matter for performance which one you chose? Let’s run an experiment.

Consider a page that generates a list of 50 items:

<ul>
    @for (int i = 0; i < 50; i++)
    {
        <li>The count is @i</li>
    }
</ul>

The code generates a long list of <li> elements and keep their indentation using the editor’s settings for tabs, spaces and tab size. Default in many editors is spaces and a tab size of 4.

With spaces it looks like this:

image

and with tabs it looks like this:

image

It’s clear to see that the indentation takes up 4 characters when spaces are used and only a single character when using tabs. If we then compare the total file size of the two variations, here’s what we get:

TabsSpacesSaving
Raw file size1403 bytes1703 bytes300 bytes/18%

Using tabs saves close to 18% of the file size over spaces.

This is, however, not a true picture of a web page. All modern web servers use compression in form of GZip or Deflate before serving HTML to the browser. So let’s look at the numbers after GZip:

TabsSpacesSaving
Raw file size1403 bytes1703 bytes300 bytes/18%
Raw file GZipped   327 bytes   332 bytes     5 bytes/1.5%

When using GZipping, the saving from using tabs over spaces is just 1.5%. It’s still a saving and it counts.

Yet again, this is not the complete story because some web developers make sure to minify the HTML by removing redundant whitespace, unneeded quotation marks etc. Normally this is done as a build step or at runtime.

So let’s minify the HTML and see what results it produces:

TabsSpacesSaving
Raw file size1403 bytes1703 bytes300 bytes/18%
Raw file GZipped  327 bytes  332 bytes     5 bytes/1.5%
Raw file minified1199 bytes1199 bytes     0 bytes/0%
Minified & GZipped  312 bytes  312 bytes     0 bytes/0%

When minified, it doesn’t matter if tabs or spaces are used, since they are all stripped away.

Conclusion

Depending on the capabilities of your server, build setup, runtime etc., here’s a little chart of what to do based on the above findings:

Use tabs or spaces
I can minifyDoesn't matter at all
I can GZip but not minifyDoesn’t matter much (tabs gives small benefit)
I can neither GZip nor minifyTabs

Keep in mind that this is a controlled experiment, so your mileage will vary.

If you want to enforce your entire team to use either tabs or spaces, then take a look at .editorconfig. There’s a plugin available for practically all editors.

In the next segment, we look at the effects of GZipping vs. minifying HTML files.