Find the slowest pages in a Stati 2 build

The metrics count the templates each page really rendered now, and the cache manifest names them.

SNP 153 #64A Filed stati cmd

shell
npx stati build --force --metrics --metrics-detailed --metrics-html
shell
latest=$(ls -t .stati/metrics/*.json | head -1)

# The ten slowest pages, with how many templates each rendered and how many times
jq -r '.pageTimings | map(select(.cached | not)) | sort_by(-.durationMs) | .[:10][] | "\(.durationMs | round) ms  \(.templatesLoaded) templates  \(.templateRenders) renders  \(.url)"' "$latest"

# Which templates the home page rendered
jq -r '.entries["/index.html"].deps[]' .stati/manifest.json

# Every page that renders the root header
jq -r '.entries[] | select(any(.deps[]; endswith("/site/partials/header.eta"))) | .path' .stati/manifest.json

templatesLoaded is the number of template files a page rendered: its layout, the shells named with stati.layout(), what it included and the Open Graph template. In Stati 1 it counted every partial the page could see, because all of them rendered for every page, so a long _partials/ folder made every page look heavy. Now a template no page includes costs nothing and isn't counted.

templateRenders counts each render. A card included ten times with different props is one template and ten renders. An include without props renders once per page and reuses its HTML after that, and those reuses add up in includeCacheHits, a total for the whole build under counts.

The manifest is the ISG cache's own record, and each entry lists the templates its page rendered, as absolute paths. That's how Stati knows which pages to rebuild when one of them changes. Keep site/ in the endswith, or site/blog/partials/header.eta matches as well.

--force matters here: a page served from the cache comes out with 0 ms and no template counts.

In the Stati docs: Templates loaded and renders, --metrics-detailed and Cache manifest.