[−][src]Crate reinda
This library helps with easily including and serving assets (like JS or CSS files) in your web application. It is fairly configurable and supports a variety of features. In particular, it can embed all assets into your executable at compile time to get an easy to deploy standalone-executable.
Quick start
To use reinda
, you mostly need to do three things: (1) define your assets
with assets!
, (2) create an Assets
instance, (3) call
Assets::get
to serve your asset.
use reinda::{assets, Assets, Config, Setup}; const ASSETS: Setup = assets! { // Folder which contains your assets, relative to your `Cargo.toml`. #![base_path = "assets"] // List of assets to include, with different settings. "index.html": { template }, "bundle.js": { hash }, }; #[tokio::main] async fn main() -> Result<(), reinda::Error> { // Initialize assets let assets = Assets::new(ASSETS, Config::default()).await?; // Retrieve specific asset. You can now send this data via HTTP or use // it however you like. let bytes /*: Option<bytes::Bytes> */ = assets.get("index.html").await?; Ok(()) }
The hash
keyword in the macro invocation means that bundle.js
will be
obtainable only with a filename that contains a hash of its content, e.g.
bundle.JdeK1YeQ90aJ.js
. This is useful for caching on the web: you can now
serve the bundle.js
with a very large max-age
in the cache-control
header. Whenever your asset changes, the URI changes as well, so the browser
has to re-request it.
But how do you include the correct JS bundle path in your HTML file? That's
what template
is for. reinda
supports very basic templating. If you
define your HTML file like this:
<html>
<head></head>
<body>
<script src="{{: path:bundle.js :}}" />
</body>
</html>
Then the {{: ... :}}
part will be replaced by the actual, hashed path of
bundle.js
. There are more uses for the template, as you can see below.
To learn more about this library, keep reading, or check out the docs for
assets!
for information on asset specification, or checkout Config
for information about runtime configuration.
Embed or loaded at runtime: dev vs. prod mode
This library has two different modes: dev (short for development) and prod (short for production). The name "prod" is deliberately not the same as "release" (the typical Rust term for it), because those two are not always the same.
There are several differences between the two modes:
dev mode | prod mode | |
---|---|---|
Normal assets | Loaded from filesystem when requested | Embedded into binary |
dynamic: true assets | Loaded from filesystem when requested | Loaded in Assets::new |
hash: true assets | filename not modified | hash inserted into filename |
Base path | config.base_path with current workdir as fallback | Given via #![base_path] |
By default, if you compile in Cargo debug mode (e.g. cargo build
), dev
mode is used. If you compile in Cargo's release mode (e.g. cargo build --release
), prod mode is used. You can instruct reinda
to always use
prod mode by enabling the feature debug-is-prod
:
reinda = { version = "...", features = ["debug-is-prod"] }
Template
reinda
has a simple template system. The input file is checked for
"fragments" which have the syntax {{: foo :}}
. The start token is actually
{{:
(note the whitespace!). So {{:foo:}}
is not recognized as fragment.
The syntax was chosen to not conflict with other template syntax that might
be present in the asset files. Please let me know if some other template
engine out there uses the {{:
syntax! Then I might change the syntax of
reinda
.
Inside a fragment, there are different replacement functions you can use:
-
include:
allows you to include the content of another file in place of the template fragment. If the included file is a template as well, that will be rendered before being included. Example:{{: include:colors.css }}
. -
path:
replaces the fragment with the potential hashed path of another asset. This only makes sense for hashed asset paths as otherwise you could just insert the path directly. Example:{{: path:bundle.js :}}
. -
var:
replaces the fragment with a runtime provided variable. SeeConfig::variables
. Example:{{: var:main-color :}}
.
Fragments have two other intended limitations: they must not contain a
newline and must not be longer than 256 characters. This is to further
prevent the template accidentally picking up start tokens that are not
intended for reinda
.
Example
index.html
:
<html>
<head>
<script type="application/json">{ "accentColor": "{{: var:color :}}" }</script>
<style>{{: include:style.css :}}</style>
</head>
<body>
<script src="{{: path:bundle.js :}}" />
</body>
</html>
style.css
body {
margin: 0;
}
And assuming bundle.js
was declared with hash
(to hash its filename) and
the config.variables
contained the entry "color": "blue"
, then the
resulting index.html
looks like this:
<html>
<head>
<script type="application/json">{ "accentColor": "blue" }</script>
<style>body {
margin: 0;
}</style>
</head>
<body>
<script src="bundle.JdeK1YeQ90aJ.js" />
</body>
</html>
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 theflate2
dependency. -
hash
(enabled by default): is required for support of filename hashing (see above). This feature adds thebas64
andsha2
dependencies. -
debug-is-prod
: see the section about "prod" and "dev" mode above.
Notes, Requirements and Limitations
reinda
actually consists of three crates:reinda-core
,reinda-macros
and the main crate. To detect whether Cargo compiles in debug or release mode,cfg(debug_assertions)
is used. All three of these crates have to be compiled with with the same setting regarding debug assertions, otherwise you will either see strange compile errors or strange runtime behavior (no UB though). This shouldn't be a concern, as all crates in your dependency graph are compiled with the same codegen settings, unless you include per-dependency overrides in yourCargo.toml
. So just don't do that.- The environment variable
CARGO_MANIFEST_DIR
has to be set when expanding theassets!
macro. Cargo does this automatically. But if you, for some reason, compile manually withrustc
, you have to set that value.
Macros
assets | Compile time configuration of assets. Returns a |
Structs
AssetId | Simple ID to refer to one asset in a |
Assets | A set of assets. |
Config | Runtime configuration. |
Info | Contains meta information about an asset. |
Setup | An opaque structure that holds metadata and (in prod mode) the included raw asset data. |
Enums
Error | All errors that might be returned by |
Type Definitions
GetError | Error type for |