Documentation ¶
Overview ¶
Package hashfs handles cache-busting of files by adding a hash of each file's contents to the filename.
How This Works: ¶
- You provide your files, as an fs.FS.
- When your binary runs, a hash is calculated of a static file's contents.
- The hash is appended to the file's name.
- The new filename is rewritten into your HTML code.
- When a browser requests a static file, using the filename-with-hash, the underlying file is looked up and served with aggressive caching headers.
Usage: ¶
- Call hashfs.NewFS before parsing your HTML templates.
- Define a func to call HFS.GetHashPath, and add it to your html/template.FuncMap.
- Modify your HTML templates to use the func defined in your html/template.FuncMap for each static file you want to cache-bust.
- Call hashfs.FileServer in your HTTP router on the endpoint you serve static files from.
# Example: See the example/example.go file in the source repo.
Example FuncMap func: ¶
func static(originalPath string) (hashPath string) { //If in development mode, just return path as-is. We will serve a non-cache- //busted version of the file since during development we refresh the browser //a lot and don't want to cache things mistakenly. if devMode { return originalPath } //Trim path, if needed. // //For example, if your static files are served off of www.example.co/static/ //and your fs.FS lists files "inside" the /static/ directory from your source //code repo, you need to remove the /static/ part of the URL to find the //matching source file. The fs.FS files will not have /static/ in their paths //since, the fs.FS just contains the files "inside" the /static/ directory. trimmedPath := strings.TrimPrefix(originalPath, "/static/") //Get the hashPath. This is where the hash is calculated, if it has not been //already (this static func was already called on this originalPath when //another template was being built in this run of your binary). hashPath := yourHashFS.GetHashPath(trimmedPath) //Now, we need to add the /static/ back to the path since that is how the //browser expects it. return path.Join("/", "static", hashPath) }
Definitions: ¶
- original path: the path to the on-disk source file.
- hash path: the path where the filename includes the hash of the file's contents.
- original name: the filename of the on-disk source file.
- hash name: the filename inclusive of the hash of the file's contents.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FileServer ¶
FileServer returns an http.Handler for serving files from our custom FS. It provides a simplified implementation of http.FileServer which is used to aggressivley cache files on the client. You would use this in the same manner as http.FileServer. Ex.: http.FileServer(http.FS(someStaticFS)) -> hashfs.FileServer(hfs).
Because FileServer is focused on small known path files, several features of http.FileServer have been removed including canonicalizing directories, defaulting index.html pages, precondition checks, & content range headers.
func HashAlgo ¶
HashAlgo specifies the algorithm to use to calculate the hash of each file's contents. Default is SHA256. MD5 is what S3 uses. This will panic if an unsupported algorithm is provided.
This should rarely be needed, since typically you don't really care about the hash algorithm. This is provided mostly for people who like looking at shorter MD5 sums.
func HashLength ¶
func HashLength(l uint) optionFunc
HashLength trims the length of the hash added to a filename. Default is the full hash length, based on the hash algorithm. Values less than 8 should not be used since a collision is highly likely. If 0 is provided, the default hash length is used.
This should rarely be needed, since typically you want as long of a hash as possible to alleviate collision concerns. This is helpful if you want shorter filenames.
func HashLocationEnd ¶
func HashLocationEnd() optionFunc
HashLocationEnd sets the hash to be appended to the end of the filename with the extension copied after the hash. script.min.js becomes script.min.js-a1b2c3...d4e5f6.js. This is the default hash location.
This is nice to keep the filename all together; there really is no downside to this location.
func HashLocationFirstPeriod ¶
func HashLocationFirstPeriod() optionFunc
HashLocationFirstPeriod sets the hash to be added in the middle of the filename, specifically at the first period in the filename. This was the original designed hash location. script.min.js becomes script-a1b2c3...d4e5f6.min.js
There is really no benefit to this location, and it is a bit ugly since it breaks up the filename.
func HashLocationStart ¶
func HashLocationStart() optionFunc
HashLocationStart sets the hash to be prepended to the beginning of the filename. script.min.js becomes a1b2c3...d4e5f6-script.min.js.
This is nice to keep the filename all together, but is a bit ugly for debugging in browser devtools since the on small/narrow screens the hash can take up all of the room where a filename will be displayed making identifying a specific file difficult.
func MaxAge ¶
MaxAge specifies the max-age value you want to set for the Cache-Control header. Default is 1 year. If an invalid value is given, the default is used.
This should rarely be needed, since typically you want to cache files for a really long time. This is provided mostly for development and testing.
Types ¶
type HFS ¶
type HFS struct {
// contains filtered or unexported fields
}
HFS represents an fs.FS with additional lookup tables for storing the calculated hashes of each file's contents. The hashes are used for aggressive client-side caching and cache-busting.
func NewFS ¶
NewFS returns the provided fs.FS with additional tooling to support calculating the hash of each file's contents for caching purposes.
optionFuncs are used for modifying the HFS. Optional funcs were used, versus just additional arguments, since this allows for future expansion without breaking existing uses and is cleaner than empty unused arguments.
func (*HFS) GetHashPath ¶
GetHashPath returns the hashPath for a provided originalPath. The hashPath is the originalPath with a hash of the file's contents added to the filename. The hash of the contents of the file located at the originalPath will be calculated if it has not already been done so. The hash will be saved to for future reuse and to prevent unnecessary recalculation of the hash each time the same originalPath is requested.
func (*HFS) Open ¶
Open returns a reference to the file at the provided path. The path could be an original path or a hash path. If a hash path is given, the original path will be looked up to return the file with.
This func is necessary for HFS to implement fs.FS. You should not need need to call this func directly.