v0.6.0
Minor Changes
-
structure.componentscontrols where Alloy looks for SSR component source files. Defaults to"components". Duringalloy serve, Alloy watches this directory and re-renders pages that use affected components. Experimental.structure: components: "elements" -
onFormatRenderedfires once per non-HTML format body after layout rendering. The payload contains{ format, content, url, path, frontMatter }. Return{ content: "..." }to replace the rendered body.alloy.hook("onFormatRendered", {}, (payload) => { if (payload.format === "json") { return { content: JSON.stringify(JSON.parse(payload.content)) }; } });onPageRenderedskips pages whoseoutputscontains only non-HTML formats. Pages with mixed outputs fire both hooks:onPageRenderedfor HTML,onFormatRenderedfor each non-HTML format. -
Breaking:
onPageRenderedreceives{ html, frontMatter, url, path }instead of a raw HTML string. Onlyhtmlis mutable. Plugins can readfrontMatterto decide whether to transform.alloy.hook("onPageRendered", {}, (page) => { if (page.frontMatter.layout === "demo") return page; page.html = page.html.replace(/<h2/g, '<h2 class="styled"'); return page; });See migration notes for the before/after.
-
Return
addDependenciesfromonPageRenderedoronContentTransformedto declare external file dependencies. Alloy tracks a reverse index and rebuilds only affected pages when those files change duringalloy dev.onFileChangedhooks can return{ invalidateByDependency: [...] }for targeted rebuilds, or{ restart: true }to restart Node bridge subprocesses.alloy.hook("onPageRendered", {}, (page) => { const result = renderSSR(page.html); return { html: result, addDependencies: [ "elements/rh-card/rh-card.js", "elements/rh-icon/rh-icon.js", ], }; });Dependencies accumulate per page per build. Removing a component tag drops that dependency on the next rebuild. Alloy normalizes paths with
filepath.Clean.Previously, changes to files outside
content/andlayouts/either triggered no rebuild or forced a full rebuild of every page. -
alloy devandalloy servewrite.alloy/server.lockon startup. If another Alloy process is watching the same directory, Alloy prints a warning with the conflicting PID, port, and akillcommand. Startup continues without blocking. Alloy removes stale lockfiles from crashed processes on the next startup.Previously, concurrent instances fought over
_site/, withclean: truefull rebuilds wiping incremental output and no error in either console.
Patch Changes
-
Alloy frees each page’s rendered HTML after writing it to disk. Previously, the build held every page body in memory until completion. A 3,000-page site averaging 500KB of output carried ~1.5GB in page bodies alone.
-
onBuildCompletepayload is now{ pageCount, duration, errors, outputDir }with camelCase keys.durationis a pre-formatted string, not nanoseconds.PagesSkippedremoved,errorsadded. Plugins that need output content should read from_site/on disk.Alloy previously piped the full rendered HTML of every page to plugins over IPC on each build.
Migration notes
onPageRendered plugins — update from (html) => string to (page) => { html }:
// Before (v0.5.x)
alloy.hook("onPageRendered", {}, (html) => {
return html.replace(/<h2/g, '<h2 class="styled"');
});
// After (v0.6.0)
alloy.hook("onPageRendered", {}, (page) => {
page.html = page.html.replace(/<h2/g, '<h2 class="styled"');
return page;
});
onBuildComplete consumers — field names are now camelCase, and duration is a string:
// Before (v0.5.x)
const ms = (result.Duration / 1e6).toFixed(0);
console.log(`Built ${result.PageCount} pages in ${ms}ms`);
// After (v0.6.0)
console.log(`Built ${result.pageCount} pages in ${result.duration}`);