Per-Page Scripts#
Instead of putting everything into one global bundle, a page (or a higher-level layout) can declare its own external scripts.
Function style#
return function (PageContext $ctx): Closure {
$ctx->js('/assets/chart.js', defer: true);
return fn (): Element => <canvas id="chart"></canvas>;
};Class style#
final class Dashboard extends LayoutComponent
{
public function render(): Element
{
$this->addJs('/assets/dashboard.js', module: true);
return <div>{...$this->getChildren()}</div>;
}
}For a page class, PageComponent::addJs(), and for a layout, LayoutComponent::addJs(), are used the same way.
Behavior#
- Output at the end of
<body>, after the main usePHP bundle,
in declaration order. A layout's scripts come before the page's, and an outer (root) layout comes before an inner one.
- src-only. The flags are
defer/async/module
(type="module"). For inline JS, use $document->addHeadHtml() (the same hook as the islands loader).
- No deduplication. If a layout and a page declare the same src,
both are output (the same "just declare, do not reconcile" policy as metadata()).
A real example on this site#
highlight.js for code highlighting is loaded only on documentation pages that have <pre><code>.
// src/Pages/docs/[slug]/page.psx
$ctx->js('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js', defer: true);The home, search, and 404 pages have no code blocks, so they do not load highlight.js. Inline / <link> such as initialization and theme CSS go on the $document->addHeadHtml() side (public/index.php), and only the library itself is declared per page — that is the division of labor. The Tailwind/dark-mode injection uses the same mechanism.
Change history (1)
- Created