diff --git a/cmd/genassets/main.go b/cmd/genassets/main.go new file mode 100644 index 00000000..3e52ca8c --- /dev/null +++ b/cmd/genassets/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "log" + "os" + "path/filepath" + + "github.com/mhsanaei/3x-ui/v2/web/assetsgen" +) + +func main() { + const ( + sourceDir = "web/assets" + outputDir = "web/public/assets" + manifestPath = "web/public/assets-manifest.json" + ) + + if err := os.RemoveAll(outputDir); err != nil { + log.Fatalf("remove stale asset output: %v", err) + } + if err := os.Remove(manifestPath); err != nil && !os.IsNotExist(err) { + log.Fatalf("remove stale asset manifest: %v", err) + } + + manifest, err := assetsgen.Generate(assetsgen.Options{ + SourceDir: sourceDir, + OutputDir: outputDir, + HashLen: 8, + }) + if err != nil { + log.Fatalf("generate fingerprinted assets: %v", err) + } + + if err := assetsgen.WriteManifest(filepath.Clean(manifestPath), manifest); err != nil { + log.Fatalf("write asset manifest: %v", err) + } +} diff --git a/web/assetsgen/generator_test.go b/web/assetsgen/generator_test.go index 4133cf13..b6b43fea 100644 --- a/web/assetsgen/generator_test.go +++ b/web/assetsgen/generator_test.go @@ -91,6 +91,38 @@ func TestGenerateClampsHashLenToSha256HexLength(t *testing.T) { } } +func TestGeneratePreservesNestedDirectories(t *testing.T) { + src := t.TempDir() + dst := t.TempDir() + + if err := os.MkdirAll(filepath.Join(src, "css"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(src, "css", "custom.min.css"), []byte("body{}\n"), 0o644); err != nil { + t.Fatal(err) + } + + manifest, err := Generate(Options{ + SourceDir: src, + OutputDir: filepath.Join(dst, "assets"), + HashLen: 8, + }) + if err != nil { + t.Fatalf("Generate returned error: %v", err) + } + + got := manifest["css/custom.min.css"] + if got == "" { + t.Fatalf("missing css/custom.min.css entry: %#v", manifest) + } + if filepath.Dir(got) != "css" { + t.Fatalf("expected nested output directory, got %q", got) + } + if filepath.Ext(got) != ".css" { + t.Fatalf("expected css extension, got %q", got) + } +} + func TestGenerateFingerprintsDotfilesWithoutLeadingExtension(t *testing.T) { src := t.TempDir() dst := t.TempDir() diff --git a/web/public/.gitkeep b/web/public/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/web/public/.gitkeep @@ -0,0 +1 @@ + diff --git a/web/public/README.md b/web/public/README.md new file mode 100644 index 00000000..7bb8646b --- /dev/null +++ b/web/public/README.md @@ -0,0 +1,12 @@ +# Generated frontend assets + +This directory is generated from `web/assets` by: + +- `go run ./cmd/genassets` + +Contents: + +- `assets/`: fingerprinted files for production embedding +- `assets-manifest.json`: logical-to-fingerprinted path mapping + +Do not edit generated files by hand.