Assets
Handling assets like images, videos, etc. in content-driven sites.
When building content-driven websites, you often have assets like images, videos, or other files that belong to a specific page or section. Managing these assets can become difficult if they are all stored in a central directory.
The AssetManager allows you to co-locate your assets with your content files. It handles the resolution of relative paths in your content and data, ensuring that they point to the correct location in the final build.
Additionally, it can process your assets during the build, like adding a hash for cache busting, scaling and optimizing images and more.
Setup
To use the AssetManager, you need to set it up in your main.dart file.
- Create an instance of
AssetManager. - Add the
assetManager.middlewareto the server app. - Add
assetManager.dataLoaderandassetManager.pageExtensionto yourContentApp.
import 'package:jaspr/server.dart';
import 'package:jaspr_content/jaspr_content.dart';
void main() {
// 1. Initialize and configure AssetManager.
final assetManager = AssetManager(
// The root directory where your assets are located. Usually, this is the same as your content directory.
directory: 'content',
// Optional: Configure which properties in your frontmatter contain asset paths.
dataProperties: {'image', 'meta.thumbnail'},
);
// 2. Add middleware to serve assets during development.
ServerApp.addMiddleware(assetManager.middleware);
runApp(ContentApp(
// ...
dataLoaders: [
// ...
// 3a. Process relative asset paths in page data.
assetManager.dataLoader,
],
extensions: [
// ...
// 3b. Process relative asset paths in page content (markdown/html).
assetManager.pageExtension,
],
));
}
Directory Structure
With AssetManager, you can organize your assets alongside your content.
content/
images/
logo.png
blog/
my-post.md
image.png
cover.jpg
media/
thumbnail.jpg
video.mp4
Usage
Once set up, you can reference your assets using relative or absolute paths. The AssetManager will automatically resolve these paths to the correct absolute URL, both during development and in the static build.
-
Relative asset paths are resolved relative to the current page's directory. This allows you to organize your assets alongside your content files.
-
Absolute paths are resolved relative to the asset root directory.
In Content (Markdown/HTML)
You can use relative paths in standard HTML tags like <img>, <video>, <audio>, and <source>. This works in both Markdown files and raw HTML.
<!-- In content/blog/my-post.md -->
# My Post
Here is an image located in the same directory:

And here is a video in a subdirectory:
<video src="media/video.mp4" controls></video>
This is an image in another directory:

These would resolve to:
content/blog/image.pngcontent/blog/media/video.mp4content/images/logo.png
In Frontmatter
If you reference assets in your page's frontmatter (e.g., for a thumbnail or cover image), you need to tell the AssetManager which properties to process using the dataProperties option during setup.
---
title: My Post
image: cover.jpg
meta:
thumbnail: media/thumbnail.jpg
---
With dataProperties: {'image', 'meta.thumbnail'}, AssetManager will resolve cover.jpg and media/thumbnail.jpg relative to the content file.
In Components
When building custom components, you can resolve asset paths using the context.resolveAsset() extension method.
import 'package:jaspr/jaspr.dart';
import 'package:jaspr_content/jaspr_content.dart';
class MyComponent extends StatelessComponent {
@override
Component build(BuildContext context) {
// Resolve 'image.png' relative to the current page.
final imagePath = context.resolveAsset('image.png');
// You can also resolve absolute paths (relative to the asset root).
final logoPath = context.resolveAsset('/images/logo.png');
return .fragment([
img(src: iconPath),
img(src: logoPath),
]);
}
}
Asset Transformers
Assets are processed during the build. By default, AssetManager uses the HashingAssetTransformer, which adds a content hash to the filename for cache busting (e.g., image.a1b2c3d4.png).
You can customize this behavior or add your own transformers by passing a list of AssetTransformers to the AssetManager constructor.
final assetManager = AssetManager(
directory: 'content',
assetTransformers: [
// Add a custom transformer.
MyCustomTransformer(),
// Apply the default hashing behavior.
HashingAssetTransformer(),
],
);
Custom Transformers
To create a custom transformer, extend AssetTransformer and implement the transform method.
class MyCustomTransformer extends AssetTransformer {
@override
Asset transform(Asset asset, [Object? aspect]) {
// Transform the asset (e.g. compress images, optimize svg, etc.)
// Return a new Asset or the same asset.
return asset;
}
}
The aspect option is passed through as a parameter from context.resolveAsset(aspect: ...) and can be used to generate asset variants, such as differently resized images.

