Skip to content
vic

arjan/exstatic

Compile static files into Elixir bytecode and serve them from memory

arjan/exstatic.json
{
"createdAt": "2015-11-08T15:24:54Z",
"defaultBranch": "master",
"description": "Compile static files into Elixir bytecode and serve them from memory",
"fullName": "arjan/exstatic",
"homepage": "",
"language": "Elixir",
"name": "exstatic",
"pushedAt": "2017-05-25T13:16:35Z",
"stargazersCount": 33,
"topics": [],
"updatedAt": "2023-01-22T20:20:56Z",
"url": "https://github.com/arjan/exstatic"
}

Serve static files from memory in the Phoenix Framework.

This extension compiles all of a project’s static assets (e.g. Javascript, HTML, images, etc) into Erlang modules and loads them into the Erlang VM, with the purpose of serving them fast and without a dependency on a filesystem.

The assumption is that there are not that many static files and they are not that big. There are no size checks done — take care that your VM settings allow the kind of memory usage.

Add exstatic to your deps:

{:exstatic, "~> 0.1"},

Then, compile your static files (by default it looks in priv/static):

mix exstatic.compile

Now, tell your endpoint to serve the compiled files.

defmodule MyApp.Endpoint do
use Phoenix.Endpoint, otp_app: :myapp
# Serve at "/" the static files from ExStatic compiled files
plug ExStatic.Plug,
at: "/"

Remember, whenever you change your files, you need to run mix exstatic.compile again.

Initial tests show that the performance is about a 70% increase compared to the vanilla Plug.Static.

Static files are compiled to the plain data and also to a gzip version. Furthermore, file metadata is also compiled into accessor functions.

The module names are checksums of the original filenames (relative to the static base path, e.g. priv/static): ExStatic.Compiled.66AGY7SLJZNP4MCP256LHNA6UWRMTGUY.beam.

Each module compiles several functions, exposing the file contents and its metadata. These functions are also accessible from the ExStatic module:

ExStatic.contents("robots.txt")
ExStatic.gzip_contents("robots.txt")
ExStatic.size("robots.txt")
ExStatic.gzip_size("robots.txt")
ExStatic.content_type("robots.txt")
ExStatic.ctime("robots.txt")
ExStatic.mtime("robots.txt")

All of these functions also exist in assertion-mode:

ExStatic.mtime!("robots.txt")

Whenever a file is not found, the function crashes (the ! variant); or {:error, :nofile, filename} is returned (the normal variant).

Furthermore, there is a ExStatic.exists? function returning a boolean to check whether a given file exists.