staticfiles is an asset manager for a web applications written in Go.

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.

Comments
  • Environment variable to enable/disable.

    Environment variable to enable/disable.

    I think we can add an env var to enable/disable staticfiles.

    Particularly useful for development vs production.

    Something like: STATIC_FILES_ENABLED=true/false.

    What do you think?

  • Problems on Windows

    Problems on Windows

    This project is wonderful and it's something I would have done - sooner or later. So thank you again.

    I'm trying to use it but I have some doubts.

    REPRODUCTION

    You can find a reproduction of my project here: https://github.com/frederikhors/test_go_staticfiles

    I'm using the amazing quicktemplate but you can try it with go templates too.

    You can find a Readme.md in the project.

    The branch master is without go-staticfiles, my doubts are in branch staticfiles.

    You have a comparison here: https://github.com/frederikhors/test_go_staticfiles/compare/staticfiles?expand=1.

    THE PROBLEM

    If I follow your usage instructions I change my code from this:

    <link rel="stylesheet" href="/static/css/base.css"/>

    to this:

    <link rel="stylesheet" href="{%s StaticFilesPrefix + Storage.Resolve("css/base.css") %}"/>

    but the result is:

    <link rel="stylesheet" href="/static/"/>

    instead of what I expect:

    <link rel="stylesheet" href="/static/css/base.934823cbc67ccf0d67aa2a2eeb798f12.css"/>

    WHAT I TRIED

    I understand this is a problem with the generated .json manifest you create.

    I need to use this:

    <link rel="stylesheet" href="{%s StaticFilesPrefix + Storage.Resolve("web\\static\\css\\base.css") %}"/>

    to get something from Storage.Resolve().

    I think because the content of .json manifest is:

    {"paths":{"web\\static\\css\\base.css":"web\\public\\web\\static\\css\\base.934823cbc67ccf0d67aa2a2eeb798f12.css"},"version":1}
    

    Now the final html is:

    <link rel="stylesheet" href="/static/web\public\web\static\css\base.934823cbc67ccf0d67aa2a2eeb798f12.css"/>

    which is wrong again because my server is serving files from web/public/web/static folder (and this is ugly itself) but on path http://localhost:3000/static without the need for useless web\public\web\static\.

    ANOTHER QUESTION

    And why the backslashes?


    Maybe a problem or maybe it's me.

    Thanks again.

  • A very long hash

    A very long hash

    It would be amazing to change from this one:

    favicon.01998662be09f970ca7aa8193a7a460c.ico

    to:

    favicon.8376ac71.ico

    I think we do not need this very long hash. What do you think?

  • Embedding files in bin.

    Embedding files in bin.

    I think a good plus would be the embedding of files in go with some of these projects: https://github.com/avelino/awesome-go/blob/master/README.md#resource-embedding.

    None of those projects has an hashing system/strategy as far as I know.

  • A bit of marketing.

    A bit of marketing.

    This project is amazing.

    We can add/suggest this project on sites or aggregators to make it grow in number of stars.

    What do you think about?

    I do suggest some sites:

    • [x] https://go.libhunt.com
    • [ ] https://awesome-go.com
    • [x] https://forum.golangbridge.org
    • [ ] Golang newsletters
    • [x] In addition we could answer some questions on StackOverflow proposing the project
Broilerplate - A template project for new Go web backend applications
Broilerplate - A template project for new Go web backend applications

Broilerplate A template project for new Go web backend applications. Can be used

Mar 28, 2022
A new way to create web applications using go and sdf framework.

SDF GO A new way to create web applications using go and sdf framework Explore the docs » View Demo · Report Bug · Request Feature Table of Contents A

Sep 27, 2022
Extract structured data from web sites. Web sites scraping.
Extract structured data from web sites. Web sites scraping.

Dataflow kit Dataflow kit ("DFK") is a Web Scraping framework for Gophers. It extracts data from web pages, following the specified CSS Selectors. You

Jan 7, 2023
記帳-PWA-web-app (Bookkeeping-PWA-web-app)
記帳-PWA-web-app (Bookkeeping-PWA-web-app)

GoKeep (bookkeeping web app) 記帳-PWA-web-app (Bookkeeping-PWA-web-app) demo link : https://bookkepping.herokuapp.com/ 測試用帳密 : tester002 , tester002 (亦可

Jan 31, 2022
log4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web servicelog4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web service
log4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web servicelog4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web service

log4jScanner Goals This tool provides you with the ability to scan internal (only) subnets for vulnerable log4j web services. It will attempt to send

Jan 5, 2023
Web terminal - A (unsafe) technical demo to export a shell to web browser
Web terminal - A (unsafe) technical demo to export a shell to web browser

Web Terminal A (unsafe) technical demo to export a shell to web browser. This pr

Dec 27, 2022
Go-web-scaffold - A simple scaffold for building web app quickly

Go-web-scaffold A simple scaffold for building web app quickly. features This sc

Jan 21, 2022
Forms is a fast, powerful, flexible, sortable web form rendering library written in golang.

forms Description forms makes form creation and handling easy. It allows the creation of form without having to write HTML code or bother to make the

Oct 2, 2022
Tiny to-do list web app written in Go

Simple Lists Simple Lists is a tiny to-do list web app. It's written in Go in an old-school way with no JavaScript, plain old HTTP GET and POST, and a

Oct 19, 2022
A simple web application written in Golang which listens on port 8080

GoWebApp It's a simple web application written in Golang which listens on port 8080 Building It can be build using the command go build -o metricsweba

Oct 21, 2021
🖖🏻 A self-hosted Quora like web application written in Go
🖖🏻 A self-hosted Quora like web application written in Go

Guora ???? A self-hosted Quora like web application written in Go 基于 Golang 类似知乎的私有部署问答应用 包含问答、评论、点赞、管理后台等功能 Quick Start (Docker Deploy) $ docker-comp

Dec 27, 2022
Simple bookmark manager built with Go
Simple bookmark manager built with Go

Shiori This project is now maintained by Dean Jackson (@deanishe). The awesome original author, @RadhiFadlillah, unfortunately no longer has the time

Jan 1, 2023
Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube
Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube

Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube

Jan 1, 2023
listmonk is a standalone high performance, self-hosted newsletter and mailing list manager with a modern dashboard. Single binary app.
listmonk is a standalone high performance, self-hosted newsletter and mailing list manager with a modern dashboard. Single binary app.

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a PostgreSQL database as its data store.

Jan 1, 2023
listmonk is a standalone, self-hosted, newsletter and mailing list manager
listmonk is a standalone, self-hosted, newsletter and mailing list manager

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a Postg

Aug 15, 2022
ArchMark is a bookmark manager that archives the bookmarked page using Monolith.
ArchMark is a bookmark manager that archives the bookmarked page using Monolith.

ArchMark ArchMark is a bookmark manager that archives the bookmarked page using Monolith. It consists of the main web proccess as well as a worker tha

Jun 21, 2022
This is a cert-manager webhook solver for DNSPod.

cert-manager-webhook-dnspod This is a cert-manager webhook solver for DNSPod. Prerequisites cert-manager >= 1.6.0 Installation Generate SecretId and S

Jan 6, 2023
📚 Task Manager App for CVWO Application (Backend)
📚 Task Manager App for CVWO Application (Backend)

Task Manager App for CVWO Application 2022 Task The task for this project is to build a fullstack task manager app, and was done over the winter break

Jan 3, 2023
Televarr - A Manager for IPTV Playlists
Televarr - A Manager for IPTV Playlists

Televarr BETA VERSION HAS BEEN RELEASED! A Manager for IPTV Playlists Televarr c

Oct 26, 2022