{"id":15440551,"url":"https://github.com/vearutop/statigz","last_synced_at":"2025-04-13T04:10:50.944Z","repository":{"id":42704875,"uuid":"324743477","full_name":"vearutop/statigz","owner":"vearutop","description":"Statigz serves pre-compressed embedded files with http in Go","archived":false,"fork":false,"pushed_at":"2024-08-15T10:50:43.000Z","size":80,"stargazers_count":73,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T08:39:04.543Z","etag":null,"topics":["compress-assets","embedded","go"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/vearutop/statigz","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vearutop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-27T11:08:17.000Z","updated_at":"2025-02-05T02:22:16.000Z","dependencies_parsed_at":"2024-06-18T16:54:10.454Z","dependency_job_id":"cb47358a-7b62-4d23-86c7-56dcc0c68391","html_url":"https://github.com/vearutop/statigz","commit_stats":{"total_commits":30,"total_committers":6,"mean_commits":5.0,"dds":0.5666666666666667,"last_synced_commit":"008281146e198a9631e15afea94f0c13e602dbd0"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vearutop%2Fstatigz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vearutop%2Fstatigz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vearutop%2Fstatigz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vearutop%2Fstatigz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vearutop","download_url":"https://codeload.github.com/vearutop/statigz/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248661704,"owners_count":21141450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compress-assets","embedded","go"],"created_at":"2024-10-01T19:14:14.650Z","updated_at":"2025-04-13T04:10:50.920Z","avatar_url":"https://github.com/vearutop.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# statigz\n\n[![Build Status](https://github.com/vearutop/statigz/workflows/test-unit/badge.svg)](https://github.com/vearutop/statigz/actions?query=branch%3Amaster+workflow%3Atest-unit)\n[![Coverage Status](https://codecov.io/gh/vearutop/statigz/branch/master/graph/badge.svg)](https://codecov.io/gh/vearutop/statigz)\n[![GoDevDoc](https://img.shields.io/badge/dev-doc-00ADD8?logo=go)](https://pkg.go.dev/github.com/vearutop/statigz)\n[![Time Tracker](https://wakatime.com/badge/github/vearutop/statigz.svg)](https://wakatime.com/badge/github/vearutop/statigz)\n![Code lines](https://sloc.xyz/github/vearutop/statigz/?category=code)\n![Comments](https://sloc.xyz/github/vearutop/statigz/?category=comments)\n\n`statigz` serves pre-compressed embedded files with http in Go 1.16 and later.\n\n## Why?\n\nSince version 1.16 Go provides [standard way](https://tip.golang.org/pkg/embed/) to embed static assets. This API has\nadvantages over previous solutions:\n\n* assets are processed during build, so there is no need for manual generation step,\n* embedded data does not need to be kept in residential memory (as opposed to previous solutions that kept data in\n  regular byte slices).\n\nA common case for embedding is to serve static assets of a web application. In order to save bandwidth and improve\nlatency, those assets are often served compressed. Compression concerns are out of `embed` responsibilities, yet they\nare quite important. Previous solutions (for example [`vfsgen`](https://github.com/shurcooL/vfsgen)\nwith [`httpgzip`](https://github.com/shurcooL/httpgzip)) can optimize performance by storing compressed assets and\nserving them directly to capable user agents. This library implements such functionality for embedded file systems.\n\nRead more in a [blog post](https://dev.to/vearutop/serving-compressed-static-assets-with-http-in-go-1-16-55bb).\n\n## Example\n\n```go\npackage main\n\nimport (\n\t\"embed\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/vearutop/statigz\"\n\t\"github.com/vearutop/statigz/brotli\"\n)\n\n// Declare your embedded assets.\n\n//go:embed static/*\nvar st embed.FS\n\nfunc main() {\n\t// Plug static assets handler to your server or router.\n\terr := http.ListenAndServe(\":80\", statigz.FileServer(st, brotli.AddEncoding))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n## Usage\n\nBehavior is based on [nginx gzip static module](http://nginx.org/en/docs/http/ngx_http_gzip_static_module.html) and\n[`github.com/lpar/gzipped`](https://github.com/lpar/gzipped).\n\nStatic assets have to be manually compressed with additional file extension, e.g. `bundle.js` would\nbecome `bundle.js.gz` (compressed with gzip) or `index.html` would become `index.html.br` (compressed with brotli).\n\n\u003e **_NOTE:_** [`zopfli`](https://github.com/google/zopfli) provides better compression than `gzip` while being\n\u003e backwards compatible with it.\n\nUpon request server checks if there is a compressed file matching `Accept-Encoding` and serves it directly.\n\nIf user agent does not support available compressed data, server uses an uncompressed file if it is available (\ne.g. `bundle.js`). If uncompressed file is not available, then server would decompress a compressed file into response.\n\nResponses have `ETag` headers (64-bit FNV-1 hash of file contents) to enable caching. Responses that are not dynamically\ndecompressed are served with [`http.ServeContent`](https://golang.org/pkg/net/http/#ServeContent) for ranges support.\n\n### Brotli support\n\nSupport for `brotli` is optional. Using `brotli` adds about 260 KB to binary size, that's why it is moved to a separate\npackage.\n\n\u003e **_NOTE:_** Although [`brotli`](https://github.com/google/brotli) has better compression than `gzip` and already\n\u003e has wide support in browsers, it has limitations for non-https servers,\n\u003e see [this](https://bugs.chromium.org/p/chromium/issues/detail?id=452335)\n\u003e and [this](https://bugzilla.mozilla.org/show_bug.cgi?id=1218924).\n\n### Runtime encoding\n\nRecommended way of embedding assets is to compress assets before the build, so that binary includes `*.gz` or `*.br`\nfiles. This can be inconvenient in some cases, there is `EncodeOnInit` option to compress assets in runtime when\ncreating file server. Once compressed, assets will be served directly without additional dynamic compression.\n\nFiles with extensions \".gz\", \".br\", \".zst\", \".gif\", \".jpg\", \".png\", \".webp\" are excluded from runtime encoding by default.\n\n\u003e **_NOTE:_** Compressing assets in runtime can degrade startup performance and increase memory usage to prepare and store compressed data.\n\n### Mounting a subdirectory\n\nIt may be convenient to strip leading directory from an embedded file system, you can do that with `statigz.FSPrefix`.\n\n```go\npackage main\n\nimport (\n\t\"embed\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/vearutop/statigz\"\n\t\"github.com/vearutop/statigz/zstd\"\n\t\"github.com/vearutop/statigz/brotli\"\n)\n\n// Declare your embedded assets.\n\n//go:embed static/*\nvar st embed.FS\n\nfunc main() {\n\t// Plug static assets handler to your server or router.\n\terr := http.ListenAndServe(\":80\", statigz.FileServer(st, brotli.AddEncoding, zstd.AddEncoding, statigz.FSPrefix(\"static\")))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n### Custom error handling\n\nError states can be handled with the `statigz.OnError` and `statigz.OnNotFound` options. These allow you to customize\nthe response sent to the client when an error occurs or when no resource is found.\n\n```go\nfileServer := statigz.FileServer(\n\tst,\n\tstatigz.OnError(func(w http.ResponseWriter, r *http.Request, err error) {\n\t\t// Handle error.\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t}),\n\tstatigz.OnNotFound(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Handle not found.\n\t\thttp.Error(w, \"Not found\", http.StatusNotFound)\n\t\t\n\t\t// Or to serve a alternative path instead you could;\n        //r.URL.Path = \"/alternative/path\"\n        //fileServer.ServeHTTP(w, r)\n\t}),\n)\n\nif err := http.ListenAndServe(\"localhost:80\", fileServer); err != nil {\n    log.Fatal(err)\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvearutop%2Fstatigz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvearutop%2Fstatigz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvearutop%2Fstatigz/lists"}