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:

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