Sacoge is a tool that makes it easy to serve your Swift Server's assets with an immutable cache policy by generating static references for each asset and adding the asset content's hash to its file name.
By serving assets with an immutable cache policy you can considerably reduce the number of requests to your server.
If you're using hummingbird, the swift-sacoge-hummingbird contains a middleware that works with sacoge's generated code.
- Add sacoge to the package dependencies:
dependencies: [
// ...
.package(url: "https://github.com/alephao/swift-sacoge.git", from: "0.3.0"),
]- Configure your target with SacogePlugin and SacogeHummingbird.
.target(
name: "MyTarget",
plugins: [
.plugin(name: "SacogePlugin", package: "swift-sacoge"),
]
)- Build
Now you can access the Asset type in your target, containing references to the assets inside the public folder.
To configure sacoge, create a file named .sacoge in the root of your project, here is an example with the default values. If you omit any of the keys, it will use the default value:
{
"from": "/",
"to": "public",
"structName": "Asset",
"ignore": [],
"skipChecksum": []
}from: The base request path to map to the file system's public directory. If thefrom -> tovalues are/static/immutable/ -> public, then requests incoming tohttps://example.com/static/immutable/img.jpgwill look into the file system'spublic/img.jpg. Default:"/"to: The path to the directory containing the static assets. If thefrom -> tovalues are/static/immutable/ -> public, then requests incoming tohttps://example.com/static/immutable/img.jpgwill look into the file system'spublic/img.jpg. Default:"public"structName: The name of the generated type that contains references to all assets. By default, if you have an asset in the root namedimg.jpgyou can reference it in your swift code by usingAsset.img_jpg. SettingstructNamewill renameAssetto something else so you would access it via{structName}.img_jpg. Default"Asset".ignore: An array with the name of files/dirs you want sacoge to ignore. It won't generate any references to the files/dirs specified here. It has to be the exact name of the file/dir likeimg.jpgorimages(there are no suppport for globs yet). Default:[].skipChecksum: By default, every file will have its content's hash added to thefromvalue, soimg.pngwould have afromvalue ofimg_abcd1234.jpg.skipChecksumworks likeignore, but instead not generating references, it won't add the checksum to thefromfile name. Default:[].
Sacoge runs a swift package build plugin, it generate a bit of swift code to help handling static/immutable assets you want to serve. This is what it is generates:
- A type
public struct Asset { ... }with information about asset locations in the local file syestem and it external access path. - Instance of the
Assettype for each asset inside your public assets folder, accessed viaAsset.{dir}.{myFile_ext}e.g.:Asset.img.my_img_png. The first 4 bytes of a SHA-256 hash of the file contents is added to the external access path, so you can serve the asset with animmutablecache policy. - A static constant in
Assetscontaining a dictionary mapping external paths to internal paths of every asset.
When referencing assets in swift code, you would following change:
func myImg() -> String {
"""
- <img src="/img/my_img.jpg">
+ <img src="\(Asset.img.my_img_jpg)">
"""
}If you get a request and want to know if there is an asset for that request, you can do the following:
// Some `Request` type that contains a URL with a PATH
let request: Request // you got this value from your server framework
guard let asset = Asset.externalToInternalMapping[request.uri.path] else {
// The asset does not exits, or was ignored by sacoge (you can configure which assets to ignore)
}
// Contains the local file system path to the asset relative to your public folder
// Example: If you have an asset at `./public/my_img.png`, the internalPath is `/my_img.png`
asset.internalPath
// The external path used in the request URL to access the asset. Contains the same value as `request.uri.path` that you used above.
asset.externalPath