Cold FeetUser Guide

Overview

Cold Feet is a support library that aids Alien-Factory in the development of libraries, frameworks and applications. Though you are welcome to use it, you may find features are missing and the documentation incomplete.

Cold Feet is an asset caching strategy for your Bed App.

  • Tired of telling clients to clear their browser cache to pick up the latest CSS and Javascript changes?
  • Don't want lame browser cache busting because you need network performance?
  • Then get Cold Feet!

Install

Install Cold Feet with the Fantom Repository Manager ( fanr ):

$ fanr install -r http://repo.status302.com/fanr/ afColdFeet

To use in a Fantom project, add a dependency to build.fan:

depends = ["sys 1.0", ..., "afColdFeet 1.0+"]

Quick Start

1). Create a text file called Example.fan:

using afIoc
using afBedSheet
using afColdFeet

class Example {
  @Inject FileHandler? fileHandler
  @Inject ColdFeet?    coldFeet

  Text coldFeetUris() {
    msg := "Normal URI   : " + fileHandler.fromServerFile(File(`Example.fan`)).toStr + "\n"
    msg += "Cold Feet URI: " + coldFeet.fromServerFile(File(`Example.fan`)).toStr
    return Text.fromPlain(msg)
  }
}

@SubModule { modules=[ColdFeetModule#] }
class AppModule {
  @Contribute { serviceType=Routes# }
  static Void contributeRoutes(OrderedConfig conf) {
    conf.add(Route(`/`, Example#coldFeetUris))
  }

  @Contribute { serviceType=FileHandler# }
  static Void contributeFileHandler(MappedConfig config) {
    config[`/`] = `./`
  }
}

class Main {
  Int main() {
    afBedSheet::Main().main([AppModule#.qname, "8080"])
  }
}

2). Run Example.fan as a Fantom script from the command line. This starts the BedSheet app server:

C:\> fan Example.fan

   ___    __                 _____        _
  / _ |  / /  _____  _____  / ___/__  ___/ /_________  __ __
 / _  | / /_ / / -_|/ _  / / __// _ \/ _/ __/ _  / __|/ // /
/_/ |_|/___//_/\__|/_//_/ /_/   \_,_/__/\__/____/_/   \_, /
           Alien-Factory BedSheet v1.3.4, IoC v1.5.4 /___/

BedSheet started up in 608ms

Bed App 'Unknown' listening on http://localhost:8080/

3). Visit http://localhost:8080/:

Normal URI: /Example.fan
Cold Feet URI: /coldFeet/RD0EXw==/Example.fan

Usage

Contribute your asset directories to the BedSheet FileHandler service as usual, but rather than hard-coding the asset URIs, let Cold Feet generate them for you.

Use the ColdFeet service to convert your asset URIs, such as /css/myStyles.css, to a Cold Feet URI like /coldFeet/XXXX/css/myStyles.css, where:

  • /coldFeet is a prefix used to identify the URI on incoming requests.
  • /XXXX is a digest, generated by Cold Feet, that changes when the asset content changes.

When a request is made for the asset using the modified URI, Cold Feet intercepts the request using BedSheet middleware and serves up the file. Cold Feet lets the browser aggressively cache it by setting a far-future expiration header (10 years by default).

If during those 10 years the asset is modified then the Cold Feet URI will change, as the XXXX digest will be updated. This forces the browser to download the new asset.

The smart ones amongst you will be asking, "But what if the browser requests an old asset URI?" Simple, Cold Feet recognises outdated URIs and responds with a 301 - Moved Permanently redirecting the browser to the new asset URI.

Note that the expiration header is only enabled in production mode.

Fail Fast

An understated advatange of using Cold Feet is that it fails fast.

Should an asset not exist on the file system (due to a bodged rename, a case sensitivity issue, or other) then Cold Feet will throw an Err on the server when the browser URI is constructed. This allows your web tests to quickly pick up these tricky errors.

The lesser appealing alternative is for the incorrect URI to be served to the browser which will subsequently recieve a 404 - Not Found. While this may not seem a big deal, these errors often go unnoticed and easily find their way into production.

Digest Strategies

Adler-32

This is the default strategy used by Cold Feet. It calculates a digest with the Adler-32 checksum algorithm. The checksum is then Base-64 encoded using the URL and filename safe alphabet.

The Adler-32 checksum was designed for speed and created for use in the zlib compression library which makes it an ideal fit for an asset digest.

Note that if your CSS file has a relative URL in it, such as:

.pretty-div {
    background-image: url(../images/pretty.png);
}

Then, under Adler-32, it will be served under the wrong digest. This is because if your CSS file is served under:

/coldFeet/x9x9x9/css/styles.css

The browser will resolve pretty.png to be under the same digest path:

/coldFeet/x9x9x9/css/../images/pretty.png

This won't do any harm, as Cold Feet will simply redirect the browser to the correct URL, but the redirect is a wasted round trip. As each redirect creates a warning, monitor your logs to find any missed relative URLs and correct as necessary. If there are many, you may wish to preprocess your CSS files to generate the Cold Feet URLS before serving.

App Version

This simple strategy ignores the asset file in question and instead returns the application's pod version. Thus, when a new application is deployed (with an new version), clients will re-download all the assets.

When not in production mode, the digest defaults to a random string.

To use, override the default digest strategy in your AppModule:

class AppModule {
    @Contribute { serviceType=ServiceOverride# }
    static Void contributeOverrides(MappedConfig config) {
        config[DigestStrategy#] = AppVersionDigest()
    }
}

Fixed Value

Use this strategy in testing. It returns a fixed / constant value each and every time.

To use, override the default digest strategy in your AppModule:

class AppModule {
    @Contribute { serviceType=ServiceOverride# }
    static Void contributeOverrides(MappedConfig config) {
        config[DigestStrategy#] = FixedValueDigest("XXX")
    }
}

Release Notes

v1.1.0

  • New: Added the Alder-32 digest strategy.
  • Chg: Renamed ChecksumStrategy -> DigestStrategy and renamed the implmentations to suit.
  • Chg: Renamed the ColdFeet service methods to match those in BedSheet's FileHandler.
  • Chg: All redirects are logged as warnings (complete with the referer). This allows you to find any missed relative references.

v1.0.0

  • New: Added assetExpiresIn config value - defaults to 10 years.
  • Chg: Uses new FileHandler methods in BedSheet 1.3.4.

v0.0.2

  • New: Preview Release