staticfiles

package module
Version: v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2019 License: MIT Imports: 12 Imported by: 1

README

Overview

Build Status Code Coverage GoDoc

staticfiles is an asset manager for a web applications written in Go. It collects asset files (CSS, JS, images, etc.) from a different locations (including subdirectories), appends hash sum of each file to its name and copies files to the target directory to be served by http.FileServer.

This approach allows to serve files without having to clear a CDN or browser cache every time the files was changed. This also allows to use aggressive caching on CDN and HTTP headers to implement so called cache hierarchy strategy. If you ever worked with Django you'll find it very similar to the staticfiles application.

Installation

go get -u github.com/catcombo/go-staticfiles/...

Usage

There are two ways to collect files:

  1. Using command line tool

    Run collectstatic --output web/staticfiles --input assets/static --input media/ --ignore **/*.pdf

    Init storage in your code:

    storage, err := staticfiles.NewStorage("web/staticfiles")
    

    Pros: Run separately from the main application and doesn't influence it startup time. It can be run on a docker container build stage, for example.

    Cons: You may forget to run the command if you didn't schedule it's start.

  2. Collect files every time the program starts

    storage, err := staticfiles.NewStorage("web/staticfiles")
    storage.AddInputDir("assets/static")
    storage.AddInputDir("media")
    storage.AddIgnorePattern("**/*.pdf")
    
    err := storage.CollectStatic()
    

    Pros: Collecting files runs automatically every time the program starts.

    Cons: Collecting files need a time. Thus, the application is running but is not accept incoming connections until copying and processing is finished.

To use in templates, define a static files prefix and register a template function to resolve storage file path from its original relative file path:

staticFilesPrefix := "/static/"
staticFilesRoot := "output/dir"

storage, err := NewStorage(staticFilesRoot)

funcs := template.FuncMap{
    "static": func(relPath string) string {
        return staticFilesPrefix + storage.Resolve(relPath)
    },
}
tmpl, err := template.New("").Funcs(funcs).ParseFiles("templates/page.html")

Now you can call static function in templates like this {{static "css/style.css"}}. The generated output will be /static/css/style.d41d8cd98f00b204e9800998ecf8427e.css (hash may vary).

Serve static files

To serve static files from the storage output directory pass storage as an argument to the http.FileServer.

storage.OutputDirList = false    // Disable directories listing, optional
handler := http.StripPrefix(staticFilesPrefix, http.FileServer(storage))
http.Handle(staticFilesPrefix, handler)

It's often required to change assets during development. staticfiles uses cached versions of the original files and to refresh files you need to run collectstatic every time you change a file. Enable development mode by set storage.Enabled = false will force storage to read original files instead of cached versions. Don't forget to enable storage back in production.

Post-processing

staticfiles post-process .css files to fix files references.

Sample input file css/style.css

@import "import.css";

div {
    background: url("../img/pix.png");
}

Output file css/style.d41d8cd98f00b204e9800998ecf8427e.css (hashes may vary)

@import "import.5f15d96d5cdb4d0d5eb6901181826a04.css";

div {
    background: url("../img/pix.3eaf17869bb51bf27bd7c91bc9853973.png");
}

Writing custom post-processing rules

You can add custom rule to post-process files. A rule is a simple function with a signature func(*Storage, *StaticFile) error which must be registered with storage.RegisterRule(CustomRule) See postprocess.go as an example of .css post-processing implementation.

Documentation

Overview

Package staticfiles is an asset manager for versioning static files in web applications.

It collects asset files (CSS, JS, images, etc.) from a different locations (including subdirectories), appends hash sum of each file to its name and copies files to the target directory to be served by http.FileServer.

This approach allows to serve files without having to clear a CDN or browser cache every time the files was changed. This also allows to use aggressive caching on CDN and HTTP headers to implement so called "cache hierarchy strategy" (https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating_and_updating_cached_responses).

Index

Constants

View Source
const ManifestFilename string = "staticfiles.json"

Manifest file name. It will be stored in the Storage.OutputDir directory.

View Source
const ManifestVersion int = 1

Variables

View Source
var ErrManifestVersionMismatch = errors.New("manifest version mismatch")

Functions

func PostProcessCSS

func PostProcessCSS(storage *Storage, file *StaticFile) error

PostProcessCSS fixes files references in CSS files to point to the hashed versions of the files in the following cases:

@import "path/file.ext"
url("path/file.ext")
sourceMappingURL=file.ext.map

Types

type ManifestScheme

type ManifestScheme struct {
	Paths   map[string]string `json:"paths"`
	Version int               `json:"version"`
}

Manifest contains mapping of the original relative file paths to the storage relative file paths.

type PostProcessRule

type PostProcessRule func(*Storage, *StaticFile) error

PostProcessRule describes the type of a post-process rule functions.

type StaticFile

type StaticFile struct {
	Path           string // Original file path
	RelPath        string // Original file path relative to the one of the Storage.inputDirs
	StoragePath    string // Storage file path
	StorageRelPath string // Storage file path relative to the Storage.OutputDir
}

type Storage

type Storage struct {
	OutputDir string

	FilesMap map[string]*StaticFile

	OutputDirList bool
	Enabled       bool
	Verbose       bool // toggles verbose output to the standard logger
	// contains filtered or unexported fields
}

func NewStorage

func NewStorage(outputDir string) (*Storage, error)

NewStorage returns new Storage initialized with the root directory and registered rule to post-process CSS files.

func (*Storage) AddIgnorePattern added in v0.4.0

func (s *Storage) AddIgnorePattern(pattern string)

func (*Storage) AddInputDir

func (s *Storage) AddInputDir(path string)

func (*Storage) CollectStatic

func (s *Storage) CollectStatic() error

CollectStatic collects files from the Storage.inputDirs (including subdirectories), appends hash sum of each file to its name, applies post-processing rules and copies files and manifest to the Storage.OutputDir directory.

func (*Storage) Open added in v0.2.0

func (s *Storage) Open(path string) (http.File, error)

Open implements http.FileSystem interface to be used primarily in http.FileServer

func (*Storage) RegisterRule

func (s *Storage) RegisterRule(rule PostProcessRule)

func (*Storage) Resolve

func (s *Storage) Resolve(relPath string) string

Resolve returns relative storage file path from the relative original file path. When storage is disabled it returns unchanged value passed in the function.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL