Asset registry

How a feature contributes a stylesheet or script to the public shell, so the page’s CSS/JS is composed from the installed features instead of hand-wired into hooks and templates.


Table of contents

  1. What it is
  2. SPL rationale. The cascade is derived, not configured
  3. The register_asset API
  4. The cascade order convention
  5. How the theme renders assets
  6. Cleared per app
  7. See also

What it is

The asset registry is a small framework module (splent_framework.assets.asset_registry) that lets each feature declare the CSS and JS files it ships from inside its init_feature(app). The feature drops the file under its blueprint’s assets/ folder (served by the blueprint asset route) and registers it; the theme renders every declared asset in the right place, deduplicated and in a deterministic order.

This replaces two old patterns, hand-written <link> tags emitted from a layout.head.css hook, and <script> blocks inlined into templates. A feature no longer injects raw markup to load its assets. It declares them as data, and the shell decides where and in what order they land.


SPL rationale. The cascade is derived, not configured

In a Software Product Line the page’s asset cascade is a point of variability resolved at derivation time from the set of installed features.

  • Install a feature that registers an asset → its <link>/<script> appears.
  • Remove it and re-derive the product → it disappears.

Two products built from different feature selections get different asset sets for free, because each set is exactly the union of what its installed features registered. There is no product-level list of stylesheets to maintain, and no risk of two features emitting a duplicate tag. Registration is deduplicated by endpoint and params.


The register_asset API

Import it from splent_framework.assets.asset_registry and call it inside init_feature(app). This is how the slider ships slider.css and slider.js.

from splent_framework.blueprints.base_blueprint import create_blueprint
from splent_framework.services.service_locator import register_service

from splent_io.splent_feature_slider.services import SliderService

slider_bp = create_blueprint(__name__)

def init_feature(app):
    from splent_framework.assets.asset_registry import register_asset

    register_service(app, "SliderService", SliderService)
    register_asset("css", "slider.assets", order=100, subfolder="css", filename="slider.css")
    register_asset("js", "slider.assets", order=100, subfolder="js", filename="slider.js")
Parameter Required Description
kind yes "css" or "js".
endpoint yes The blueprint’s asset route, e.g. "slider.assets".
order no Load order; lower comes first. Defaults to 100. See the cascade convention below.
**params no url_for params for the asset route, e.g. subfolder="css", filename="slider.css".

The call is idempotent. The registry dedupes by (kind, endpoint, params), so registering the same asset twice does not emit a duplicate tag.

Companion functions.

  • get_assets(kind). Returns the resolved, deduplicated asset URLs of a kind, ordered by (order, endpoint). url_for is resolved at call time, so this is called from the template (inside a request context); an asset whose route can’t be resolved is silently skipped, not raised.
  • clear_assets(). Empties the registry.

You rarely call these two yourself. get_assets is exposed as a Jinja global and used by the theme; clear_assets() is called per app at feature-load (see below).


The cascade order convention

order governs the cascade deterministically. The convention is as follows.

Layer order Wins
Theme base ~0 first (lowest priority)
Features ~100 middle
Skins ~200 last (highest priority)

A skin therefore ships its skin.css via register_asset(..., order=200) so it loads after every feature’s CSS and can override it. Features stick to the default 100; the theme’s own base CSS sits near 0.


How the theme renders assets

The public shell (public_base.html in the theme) pulls the registered URLs straight from the Jinja globals. CSS goes in the <head>.

{% for href in get_assets('css') %}<link rel="stylesheet" href="{{ href }}">{% endfor %}

…and JS is emitted (deferred) just before </body>.

{% for src in get_assets('js') %}<script defer src="{{ src }}"></script>{% endfor %}

Because the URLs are already ordered and deduped, the template just iterates.


Cleared per app

Like the nav registry, the asset registry is cleared per app at feature-load. the framework’s FeatureManager calls clear_assets() in register_features() before loading each product’s features. The registry therefore only ever holds the assets of this product’s installed features, so a product only emits the CSS/JS it actually uses.


See also


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es