biagiojs

Optimization loop

biagiojs closes the loop between production traffic and the next build. Field data in reports/ recalibrates component weights and hydration thresholds — no manual graph edits.

deploy → real users → reports/ → biagio build → tuned HTML → deploy

Report files

Place JSON under reports/ (watched in dev):

FileSourceEffect on build
analytics.jsonYour analytics exportinteractionProbability ← observed CTR per component
heatmap.jsonAttention / scroll mapsconversionWeight nudged ±0.2
searchconsole.jsonGSC top landing componentsseoWeight +0.15 for matched IDs
crux.jsonCrUX / PageSpeed InsightsHydration thresholds raised or relaxed

Example analytics.json:

{
  "componentClicks": {
    "hero-cta": 0.18,
    "newsletter": 0.03
  }
}

Example crux.json (from pull-vitals):

{
  "p75": { "lcp": 2800, "inp": 220, "cls": 0.05 }
}

Slow field INP/LCP → less eager hydration (higher thresholds). Fast sites hydrate more aggressively.

The build log prints every optimizer decision — inspectable, deterministic, no black box.

biagio pull-vitals

Fetch real-user CrUX percentiles into reports/crux.json:

npx biagio pull-vitals https://yoursite.com/ .

Optional PSI_API_KEY env var for PageSpeed Insights API quota.

Run after deploy (or on a schedule in CI) so the next build reflects how users actually experience the site.

Per-locale reports

For multilingual sites, override per market:

reports/it/analytics.json
reports/de/crux.json

See Internationalization.

A/B experiments

Server-side assignment — zero flicker, zero CLS, no client-side bucketing JS.

export default function ({ ExperimentEngine, userId }) {
  const ab = new ExperimentEngine({ userId })
    .define('hero_cta', ['control', 'urgency'], { weights: [0.5, 0.5] });

  const cta = ab.pick('hero_cta', {
    control: () => '<button class="btn">Buy</button>',
    urgency: () => '<button class="btn">Buy now — free shipping</button>',
  });

  // … add cta to graph, optionally ab.beacon() in head for analytics
}
  • Same userId → same variant (deterministic FNV hash)
  • Output wrapped in data-cvw-exp / data-cvw-variant for measurement
  • ab.beacon() exposes window.__CVW_EXPERIMENTS__ to your analytics tag

Combine experiments with business weights: winning variants can inform declared weights in the next iteration.

biagio analyze

After build, inspect what shipped:

npx biagio analyze

Writes dist/.biagio-analyze.json — HTML weight per page, island counts, asset totals. When site.optimize.bundleClasses is enabled, the report also shows class bundle aliases and raw HTML bytes saved per route.

Class bundle (opt-in)

For utility-heavy markup (e.g. repeated Tailwind-like class strings), enable:

// biagio.config.js
export default {
  site: {
    optimize: {
      bundleClasses: true,
      bundleMinRepeat: 3,   // default
      bundleMinTokens: 2,   // default — skip single-class attrs
    },
  },
};

At build time biagiojs:

  1. Finds identical class="flex items-center …" values that appear ≥ bundleMinRepeat times
  2. Checks that each token has a rule in a page <style> block (top-level in .biagio, or head from .page.js)
  3. Replaces them with short aliases (u-0, u-1, …) and injects consolidated CSS
  4. Runs purge afterward so unused utility rules drop out of component styles

Skip an element with data-cvw-no-bundle. Classes inside <template> are never bundled (client-only widgets).

Impact: mostly raw HTML savings; gzip/Brotli already compress repeated strings well. Best on landing pages with many identical utility chains. See demo/pages/bundle-demo.page.biagio.

Pair with Lighthouse on biagio preview for lab vs field comparison.

Related