Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(assets): recalculate assets hashes in development mode #26

Merged
merged 2 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions assets/fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import (

// PathFor returns the fingerprinted path for a given
// file. If the path passed contains the hash it will
// return the same path.
// return the same path only in GO_ENV=development

// filename to open should be the file without the prefix
// filename for the map should be the file without the prefix
// filename returned should be the file with the prefix
func (m *manager) PathFor(name string) (string, error) {
normalized := m.normalize(name)
if hashed, ok := m.fileToHash[normalized]; ok {
return path.Join(m.servingPath, hashed), nil

if hashed, ok := m.fileToHash[normalized]; ok && os.Getenv("GO_ENV") != "development" {
return path.Join("/", m.servingPath, hashed), nil
}

// Compute the hash of the file
Expand All @@ -38,6 +39,12 @@ func (m *manager) PathFor(name string) (string, error) {

m.fmut.Lock()
defer m.fmut.Unlock()

// Delete previous asset hash from map
if old, exists := m.fileToHash[normalized]; exists && old != filename {
delete(m.HashToFile, old)
}

m.fileToHash[normalized] = filename
m.HashToFile[filename] = normalized

Expand Down
89 changes: 88 additions & 1 deletion assets/fingerprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestFingerprint(t *testing.T) {
assetsPath := "/files/"
assetsPath := "/files"
m := assets.NewManager(fstest.MapFS{
"main.js": {Data: []byte("AAA")},
"other/main.js": {Data: []byte("AAA")},
Expand Down Expand Up @@ -125,6 +125,45 @@ func TestFingerprint(t *testing.T) {
}
})

t.Run("HandlerPattern", func(t *testing.T) {
cases := []struct {
pattern string
expected string
}{
{"/", ""},
{"/", ""},

{"files", "/files/"},
{"/files/", "/files/"},
{"files/", "/files/"},
{"/files/", "/files/"},

{"files/path", "/files/path/"},
{"/files/path", "/files/path/"},
{"files/path/", "/files/path/"},
{"/files/path/", "/files/path/"},
}

for _, c := range cases {
m := assets.NewManager(fstest.MapFS{}, c.pattern)
if m.HandlerPattern() != c.expected {
t.Errorf("Expected %q to equal %q", m.HandlerPattern(), c.expected)
}
}
})

t.Run("HandlerPattern with root serving path", func(t *testing.T) {
m := assets.NewManager(fstest.MapFS{}, "/")
if m.HandlerPattern() == "/" {
t.Errorf("Expected empty string, got %s", m.HandlerPattern())
}

m = assets.NewManager(fstest.MapFS{}, "public")
if m.HandlerPattern() != "/public/" {
t.Errorf("Expected '/public/', got %s", m.HandlerPattern())
}
})

t.Run("PathFor normalize file path", func(t *testing.T) {
cases := []struct {
servingPath string
Expand Down Expand Up @@ -186,4 +225,52 @@ func TestFingerprint(t *testing.T) {
}
}
})

t.Run("recalculate hashed files only un development", func(t *testing.T) {
fsMap := fstest.MapFS{
"main.js": {Data: []byte("AAA")},
}

m := assets.NewManager(fsMap, assetsPath)

t.Run("in development mode should recalculate the asset hash", func(t *testing.T) {
t.Setenv("GO_ENV", "development")

a, err := m.PathFor("main.js")
if err != nil {
t.Errorf("Expected nil, got %s", err)
}

fsMap["main.js"] = &fstest.MapFile{Data: []byte("BBB")}

b, err := m.PathFor("main.js")
if err != nil {
t.Errorf("Expected nil, got %s", err)
}

if a == b {
t.Errorf("Expected %s to not equal %s", a, b)
}
})

t.Run("in other env should not recalculate the asset hash", func(t *testing.T) {
t.Setenv("GO_ENV", "production")

a, err := m.PathFor("main.js")
if err != nil {
t.Errorf("Expected nil, got %s", err)
}

fsMap["main.js"] = &fstest.MapFile{Data: []byte("CCC")}

b, err := m.PathFor("main.js")
if err != nil {
t.Errorf("Expected nil, got %s", err)
}

if a != b {
t.Errorf("Expected %s to equal %s", a, b)
}
})
})
}
11 changes: 5 additions & 6 deletions assets/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ func NewManager(embedded fs.FS, servingPath string) *manager {
servingPath = "/"
}

if !strings.HasPrefix(servingPath, "/") {
servingPath = "/" + servingPath
}

if !strings.HasSuffix(servingPath, "/") {
servingPath += "/"
servingPath = strings.Trim(servingPath, "/")
if servingPath == "" {
servingPath = "/"
} else {
servingPath = "/" + servingPath + "/"
}

return &manager{
Expand Down
Loading