Render JS Once Per Page
Since Hyvä 1.3.6
Hyvä typically co-locates JavaScript with its HTML. However, when HTML renders multiple times (e.g., product lists), this can duplicate JS in the page source. To avoid this, you can split JS into a separate template and render it only once.
Since Hyvä 1.3.6, the Hyva\Theme\ViewModel\PageJsDependencyRegistry view model allows rendering JS dependencies in the before-body-end container.
Layout XML
Declare JavaScript dependencies in Layout XML using the hyva_js_block_dependencies block argument. This specifies block names to be rendered automatically when the parent block renders.
For example:
<block class="Magento\Catalog\Block\Product\AbstractProduct" name="product_list_item"
template="Magento_Catalog::product/list/item.phtml">
<arguments>
<argument name="hyva_js_block_dependencies" xsi:type="array">
<item name="category.products.list.js.wishlist" xsi:type="boolean">true</item>
</argument>
</arguments>
</block>
The item key is the JS dependency block name. Its value must be an integer, boolean, or non-empty string. Setting it to false, null, or an empty string prevents rendering, allowing theme overrides.
Similarly, use the hyva_js_template_dependencies property for template dependencies.
PHP: Block Dependency
Beware of the block_html cache
If the template block or a parent block is cached in the block_html, the JS dependency will not be rendered if the template is served from the cache.
For this reason, it is more reliable to use Layout XML to declare JS dependencies.
You can also declare JavaScript dependencies for a block using PHP within a template. Use the $pageJsRegistry->setBlockNameDependency() method to render a JS block only if the current template is rendered.
For example:
$pageJsRegistry = $viewModels->require(\Hyva\Theme\ViewModel\BlockJsDependencies::class);
$pageJsRegistry->setBlockNameDependency($block, 'category.products.list.js.wishlist');
This will render the block named category.products.list.js.wishlist in the before.body.end container.
PHP: Template Dependency
To specify a template directly, use the setBlockTemplateDependency method:
For example:
$pageJsRegistry = $viewModels->require(\Hyva\Theme\ViewModel\BlockJsDependencies::class);
$pageJsRegistry->setBlockTemplateDependency($block, 'Magento_Catalog::product/list/js/wishlist.phtml');
Note: This method shares the same block_html cache considerations as setBlockNameDependency().