Serving gzipped CSS and JavaScript from Amazon CloudFront via S3

I've been looking for ways of making my site load faster and one way that I'd like to explore is making greater use of Cloudfront.

Because Cloudfront was originally not designed as a custom-origin CDN and because it didn't support gzipping, I have so far been using it to host all my images, which are referenced by their Cloudfront cname in my site code, and optimized with far-futures headers.

CSS and javascript files, on the other hand, are hosted on my own server, because until now I was under the impression that they couldn't be served gzipped from Cloudfront, and that the gain from gzipping (about 75 per cent) outweighs that from using a CDN (about 50 per cent): Amazon S3 (and thus Cloudfront) did not support serving gzipped content in a standard manner by using the HTTP Accept-Encoding header that is sent by browsers to indicate their support for gzip compression, and so they were not able to Gzip and serve components on the fly.

Thus I was under the impression, until now, that one had to choose between two alternatives:

  1. move all assets to the Amazon CloudFront and forget about GZipping;

  2. keep components self-hosted and configure our server to detect incoming requests and perform on-the-fly GZipping as appropriate, which is what I chose to do so far.

There were workarounds to solve this issue, but essentially these didn't work. [link].

Now, it seems Amazon Cloudfront supports custom origin, and that it is now possible to use the standard HTTP Accept-Encoding method for serving gzipped content if you are using a Custom Origin [link].

I haven't so far been able to implement the new feature on my server. The blog post I linked to above, which is the only one I found detailing the change, seems to imply that you can only enable gzipping (bar workarounds, which I don't want to use), if you opt for custom origin, which I'd rather not: I find it simpler to host the coresponding fileds on my Cloudfront server, and link to them from there. Despite carefully reading the documentation, I don't know:

  • whether the new feature means the files should be hosted on my own domain server via custom origin, and if so, what code setup will achieve this;

  • how to configure the css and javascript headers to make sure they are served gzipped from Cloudfront.


答案 1

UPDATE: Amazon now supports gzip compression, so this is no longer needed. Amazon Announcement

Original answer:

The answer is to gzip the CSS and JavaScript files. Yes, you read that right.

gzip -9 production.min.css

This will produce . Remove the , upload to S3 (or whatever origin server you're using) and explicitly set the header for the file to .production.min.css.gz.gzContent-Encodinggzip

It's not on-the-fly gzipping, but you could very easily wrap it up into your build/deployment scripts. The advantages are:

  1. It requires no CPU for Apache to gzip the content when the file is requested.
  2. The files are gzipped at the highest compression level (assuming ).gzip -9
  3. You're serving the file from a CDN.

Assuming that your CSS/JavaScript files are (a) minified and (b) large enough to justify the CPU required to decompress on the user's machine, you can get significant performance gains here.

Just remember: If you make a change to a file that is cached in CloudFront, make sure you invalidate the cache after making this type of change.


答案 2

My answer is a take off on this: http://blog.kenweiner.com/2009/08/serving-gzipped-javascript-files-from.html

Building off skyler's answer you can upload a gzip and non-gzip version of the css and js. Be careful naming and test in Safari. Because safari won't handle or files..css.gz.js.gz

site.js and site.js.jgz and site.css and site.gz.css (you'll need to set the content-encoding header to the correct MIME type to get these to serve right)

Then in your page put.

<script type="text/javascript">var sr_gzipEnabled = false;</script> 
<script type="text/javascript" src="http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr.gzipcheck.js.jgz"></script> 

<noscript> 
  <link type="text/css" rel="stylesheet" href="http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css">
</noscript> 
<script type="text/javascript"> 
(function () {
    var sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css';
    if (sr_gzipEnabled) {
      sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css.gz';
    }

    var head = document.getElementsByTagName("head")[0];
    if (head) {
        var scriptStyles = document.createElement("link");
        scriptStyles.rel = "stylesheet";
        scriptStyles.type = "text/css";
        scriptStyles.href = sr_css_file;
        head.appendChild(scriptStyles);
        //alert('adding css to header:'+sr_css_file);
     }
}());
</script> 

gzipcheck.js.jgz is just sr_gzipEnabled = true; This tests to make sure the browser can handle the gzipped code and provide a backup if they can't.

Then do something similar in the footer assuming all of your js is in one file and can go in the footer.

<div id="sr_js"></div> 
<script type="text/javascript"> 
(function () {
    var sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js';
    if (sr_gzipEnabled) {
       sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js.jgz';
    }
    var sr_script_tag = document.getElementById("sr_js");         
    if (sr_script_tag) {
    var scriptStyles = document.createElement("script");
    scriptStyles.type = "text/javascript";
    scriptStyles.src = sr_js_file;
    sr_script_tag.appendChild(scriptStyles);
    //alert('adding js to footer:'+sr_js_file);
    }
}());
</script> 

UPDATE: Amazon now supports gzip compression. Announcement, so this is no longer needed. Amazon Announcement