Crate reinda

source ·
Expand description

This library helps with managing assets (like JS or CSS files) in your web application. It allows you to embed the files directly into your executable (for ease of deployment), optionally in compressed form. reinda can also insert a hash into filenames to facilitate powerful web caching. In development mode, all files are loaded dynamically, avoiding recompilation and thus reducing feedback cycles.

§Quick start

There are three main steps:

  1. Use embed! to embed certain files into your binary.
  2. Configure your assets via Builder and build Assets.
  3. Serve your assets via Assets::get
use reinda::Assets;

// Step 1: specify assets that you want to embed into the executable.
const EMBEDS: reinda::Embeds = reinda::embed! {
    // Folder which contains your assets, relative to your `Cargo.toml`.
    base_path: "assets",

    // List files to embed. Supports glob patterns
    files: [
        "index.html",
        "bundle.js",
        "icons/*.svg",
    ],
};


#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Step 2: Configure your assets next. In this example, all embedded
    // assets are just added, without any special configuration. Note though
    // that the first argument, the HTTP path, can differ.
    let mut builder = Assets::builder();
    builder.add_embedded("index.html", &EMBEDS["index.html"]);
    builder.add_embedded("static/main.js", &EMBEDS["bundle.js"]).with_hash();
    builder.add_embedded("static/icons/", &EMBEDS["icons/*.svg"]);

    // You can also add assets not mentioned in `embed!` which are then
    // always loaded at runtime.
    builder.add_file("img/logo.svg", std::env::current_dir().unwrap().join("logo.svg"));

    // Load & prepare all assets.
    let assets = builder.build().await?;


    // Step 3: serve assets (of course, this would be in an HTTP request handler).
    let asset = assets.get("index.html").unwrap();
    let bytes = asset.content().await?;

    // ...
    Ok(())
}

For a longer and more practical example, see examples/main.rs in the repository.

In practice, you likely want to use EntryBuilder::with_hash for most of your assets. And then use EntryBuilder::with_modifier and/or EntryBuilder::with_path_fixup to fix the references across files.

§Prod vs. dev mode

Reinda operates in one of two modes: prod or dev. Prod mode is enabled if you are building in release mode (e.g. cargo build --release) or if you enabled the crate feature always-prod. Otherwise, dev mode is enabled.

The mode influences the behavior of reinda significantly. The following table describes those differences, though you likely don’t need to worry about the details too much.

ProdDev
SummaryEmbed assets & optimize for speedDynamically load assets for faster feedback cycles
embed!Loads & embeds assets into executableOnly stores asset paths
with_hashHash inserted into filenameNo hashes inserted
Builder::buildLoads all assets, applies modifiers, calculates hashesDoes hardly anything, keeps storing paths
Assets::getHashmap lookupChecks if path matches any assets or globs
Asset::contentJust returns the already loaded BytesLoads file from file system, applies modifier

§Glossary: kinds of paths

This library is dealing with different kind of paths, which could be confused for one another. Here are the terms these docs try to use:

  • FS path: a proper path referring to one file on the file system.
  • Embed pattern: what you specify in files inside embed!: could either be an FS path (referring to a single file) or contain a glob that matches any number of files.
  • HTTP path: the path under which assets are reachable.
    • unhashed HTTP path: HTTP path before hashes are inserted. This is what you specify in all Builder::add_* methods.
    • hashed HTTP path: HTTP path after inserting hashes (if configured). This is what you pass to Assets::get and get inside Assets::iter. Even for assets without a hashed filename, the same term is used for consistency. Meaning: for non-hashed assets or in dev mode, the hashed and unhashed HTTP path is exactly the same.

§Cargo features

  • compress (enabled by default): if enabled, embedded files are compressed. This often noticably reduces the binary size of the executable. This feature adds the brotli dependency.

  • hash (enabled by default): is required for support of filename hashing (see above). This feature adds the base64 and sha2 dependencies.

  • always-prod: enabled prod mode even when compiled in debug mode. See the section about “prod” and “dev” mode above.

§Notes, Requirements and Limitations

  • reinda consists of two crates: reinda-macros and the main crate. Both crates have to be compiled with the same dev/prod mode. Cargo does this correctly by default, so don’t worry about this unless you add per-dependency overrides.
  • The environment variable CARGO_MANIFEST_DIR has to be set when expanding the embed! macro. Cargo does this automatically. But if you, for some reason, compile manually with rustc, you have to set that value.

Modules§

  • Utility functions.

Macros§

  • Embeds files into the executable.

Structs§

  • An fully prepared asset.
  • Collection of assets, mapping from hashed HTTP paths to assets. Basically a virtual file system.
  • Helper to build Assets.
  • A single file embedded by embed!.
  • A glob entry embedded by embed!.
  • Collection of files embedded into the executable by embed!.
  • Returned by the various Builder::add_* functions, allowing you to configure added assets.
  • Passed to the modifier closure, e.g. allowing you to resolve unhashed HTTP paths to hashed ones.

Enums§