hashembed

package module
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2023 License: MIT Imports: 10 Imported by: 0

README

Hash Embed

Build and Test Coverage Status GitHub Tag License Docs

Logo

hashembed is an embed.FS with support for reading files with virtual content hashes embedded in the file name.

hashembed is useful if you are embedding static assets directly into your application and want to facilitate serving these files with very long duration client-side caching.

Usage

package main

import (
  "embed"
  "github.com/42z-io/hashembed"
)

//go:embed testdata/*
var embedded embed.FS

func main() {
  embedded, _ := hashembed.Generate(embedded)
  path := embedded.GetHashedPath("testdata/test.css")
  fmt.Printf(path)
  // Output: testdata/test.8d77f04c3be2abcd554f262130ba6c30f277318e66588b6a0d95f476c4ae7c48.css
  data, _ := embedded.ReadFile(path)
  fmt.Println(string(data[:])
  // Output: body { width: 100%; }
}

Use Case

Here is a psuedo example using Fiber, and Templ

//go:embed dist/*
var data embed.FS
var hashedData := hashembed.Generate(data)

// Template
templ {
    <script src={ "/static/" + hashedData.GetHashedPath("dist/my_file.css") }>
}
// <script src="/static/dist/my_file.HASH_CODE_HERE.css">

// Filesystem middleware
app.Use("/static", filesystem.New(
  filesystem.Config{
      Root:       http.FS(hashedData),
      Browse:     false,
      MaxAge:     600000,
  }
))

Documentation

Overview

hashembed is an embed.FS with support for reading files with virtual content hashes embedded in the file name.

hashembed is useful if you are embedding static assets directly into your application and want to facilitate serving these files with very long duration client-side caching.

File Hashing

Files are hashed when you call Generate.

You can provide a custom file hasher by providing a function that matches FileHasher.

There are several built-in hashers:

File Renaming

Files are renamed to include their hash when you call Generate.

You can provide a custom file renamer by providing a function that matches FileRenamer.

There are two built-in renaming mechanims:

Examples

Example
// use go:embed
// var embeded embed.FS
embedded, _ := Generate(embedded)
path := embedded.GetHashedPath("testdata/test.css")
data, _ := embedded.ReadFile(path)
fmt.Printf("%s\n%s\n", path, string(data[:]))
Output:

testdata/test.8d77f04c3be2abcd554f262130ba6c30f277318e66588b6a0d95f476c4ae7c48.css
body { width: 100%; }
Example (Configured)
// use go:embed
// var embeded embed.FS
embedded, _ := Generate(embedded, Config{
	// Extensions not in this list will not be given content-hashes
	AllowedExtensions: []string{"css", "txt"},
	// Mechanism to control the hash
	Hasher: Crc32Hasher,
	// Mechanism to control the naming of the content-hashed files
	Renamer: FullNameRenamer,
})
path := embedded.GetHashedPath("testdata/test.css")
data, _ := embedded.ReadFile(path)
fmt.Printf("%s\n%s\n", path, string(data[:]))
Output:

testdata/7f2cded6.css
body { width: 100%; }

Index

Examples

Constants

This section is empty.

Variables

View Source
var ConfigDefault = Config{
	Hasher:            Sha256Hasher,
	Renamer:           ExtensionRenamer,
	AllowedExtensions: []string{"js", "json", "png", "bmp", "jpeg", "jpg", "css", "ico"},
}

Default configuration for HashedFS.

Functions

func Crc32Hasher

func Crc32Hasher(data []byte) (string, error)

Generate a hash for the data using IEEE CRC 32.

func ExtensionRenamer

func ExtensionRenamer(file PathedDirEntry, hash string) string

Rename a file by injecting the hash before the extension.

my/path/test.css -> my/path/test.$hash.css

func FullNameRenamer

func FullNameRenamer(file PathedDirEntry, hash string) string

Rename a file by replacing the name with the hash.

my/path/test.css -> my/path/$hash.css

func Sha256Hasher

func Sha256Hasher(data []byte) (string, error)

Generate a hash for the data using SHA-256.

Types

type Config

type Config struct {
	Hasher            FileHasher  // mechanism used to hash the file
	Renamer           FileRenamer // mechanism used to rename the file
	AllowedExtensions []string    // a list of extensions that will have content hashes generated for
}

Config holds the configuration for the HashedFS.

type FileHasher

type FileHasher = func(data []byte) (string, error)

Interface for a FileHasher.

type FileRenamer

type FileRenamer func(entry PathedDirEntry, hash string) string

Functional interface for a custom FileRenamer.

type HashedFS added in v0.0.2

type HashedFS struct {
	// contains filtered or unexported fields
}

HashedFS is an embed.FS with support for reading files with virtual content hashes embedded in the file name.

func Generate

func Generate(fs embed.FS, cfgs ...Config) (*HashedFS, error)

Generate will create a new instance of HashedFS using Config (if provided) or ConfigDefault if not provided.

func (HashedFS) GetActualPath added in v0.0.2

func (f HashedFS) GetActualPath(path string) string

GetActualPath will convert the content hashed path into the actual path.

If the actual path is not found it will return the provided path.

Example
fmt.Println(
	hashedEmbeded.GetActualPath("testdata/test.8d77f04c3be2abcd554f262130ba6c30f277318e66588b6a0d95f476c4ae7c48.css"),
)
Output:

testdata/test.css

func (HashedFS) GetHashedPath added in v0.0.2

func (f HashedFS) GetHashedPath(path string) string

GetHashedPath will convert the actual path into the content hashed path.

If the hashed path is not found it will return the provided path.

Example
fmt.Println(
	hashedEmbeded.GetHashedPath("testdata/test.css"),
)
Output:

testdata/test.8d77f04c3be2abcd554f262130ba6c30f277318e66588b6a0d95f476c4ae7c48.css

func (HashedFS) GetIntegrity added in v0.0.4

func (f HashedFS) GetIntegrity(path string) string

GetIntegrity will get the SHA-256 integrity hash (base64 encoded) for the specified path.

Will only find files matched by the [Config.AllowedExtensions] list.

If the hashed path is not found it will return a blank string.

func (HashedFS) Open added in v0.0.2

func (f HashedFS) Open(name string) (fs.File, error)

See embed.FS.Open

This will call [GetActualPath] on the file to get the correct name.

func (HashedFS) ReadDir added in v0.0.2

func (f HashedFS) ReadDir(name string) ([]fs.DirEntry, error)

See embed.FS.ReadDir

Note: This will only return files that actually exist in the embed.FS - hashed files are "virtual"

func (HashedFS) ReadFile added in v0.0.2

func (f HashedFS) ReadFile(name string) ([]byte, error)

See embed.FS

This will call HashedFS.GetActualPath on the file to get the correct name.

type PathedDirEntry

type PathedDirEntry struct {
	// contains filtered or unexported fields
}

An fs.DirEntry that keeps track of the root path.

Provides mechanisms to get the root, full path, and extension of the entry.

func NewPathedDirEntry

func NewPathedDirEntry(entry fs.DirEntry, rootPath string) PathedDirEntry

Create a new PathedDirEntry from an fs.DirEntry.

func (PathedDirEntry) FullPath

func (p PathedDirEntry) FullPath() string

Get the full path including the root to the entry.

func (PathedDirEntry) Info

func (p PathedDirEntry) Info() (fs.FileInfo, error)

See fs.DirEntry.Info

fs.FileInfo.Name will NOT contain the content hash embedded in the file name.

func (PathedDirEntry) IsDir

func (p PathedDirEntry) IsDir() bool

See fs.DirEntry.IsDir

func (PathedDirEntry) Name

func (p PathedDirEntry) Name() string

See fs.DirEntry.Name

This will NOT contain the content hash embedded in the file name.

func (PathedDirEntry) NameAndExtension

func (p PathedDirEntry) NameAndExtension() (string, string)

Get the name (without extension) and the extension of the entry.

func (PathedDirEntry) RootPath

func (p PathedDirEntry) RootPath() string

Get the root path.

func (PathedDirEntry) Type

func (p PathedDirEntry) Type() fs.FileMode

See fs.DirEntry.Type

Jump to

Keyboard shortcuts

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