From b889f5dd1fbbd9caba62165d51dea7f20b38b8d4 Mon Sep 17 00:00:00 2001 From: JaJuMa Date: Thu, 16 Oct 2025 11:46:55 +0700 Subject: [PATCH 1/4] feat: add prerender mode support and corresponding script for customer data reinitialization --- ViewModel/SpeculationRules.php | 39 ++++++++++++++++++- .../templates/speculation-rules.phtml | 10 ++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/ViewModel/SpeculationRules.php b/ViewModel/SpeculationRules.php index cd98f2d..e3230af 100644 --- a/ViewModel/SpeculationRules.php +++ b/ViewModel/SpeculationRules.php @@ -11,7 +11,9 @@ class SpeculationRules implements ArgumentInterface { protected const CONFIG_PATH = 'system/speculation_rules/'; - protected const FETCH_MODES = ['prefetch', 'prerender']; + protected const MODE_PREFETCH = 'prefetch'; + protected const MODE_PRERENDER = 'prerender'; + protected const FETCH_MODES = [self::MODE_PREFETCH, self::MODE_PRERENDER]; protected const EAGERNESS_MODES = ['conservative', 'moderate', 'eager']; public function __construct( @@ -35,7 +37,7 @@ public function getMode(): string return $mode; } - return 'prefetch'; + return self::MODE_PREFETCH; } public function getEagerness(): string @@ -49,6 +51,39 @@ public function getEagerness(): string return 'moderate'; } + /** + * Check if the current mode is prerender + * + * @return bool + */ + public function isPrerenderMode(): bool + { + return $this->getMode() === self::MODE_PRERENDER; + } + + /** + * Get prerendering change script for customer data reinitialization + * Returns script only when prerender mode is enabled + * + * @return string + */ + public function getPrerenderingScript(): string + { + if (!$this->isPrerenderMode()) { + return ''; + } + + return << { + if (document.prerendering) { + document.addEventListener("prerenderingchange", () => { + require('Magento_Customer/js/customer-data').init(); + }, { once: true }); + } + })(); + JS; + } + public function getSpeculationRules(): array { // Possible future development: add support for multiple modes and rulesets at once. diff --git a/view/frontend/templates/speculation-rules.phtml b/view/frontend/templates/speculation-rules.phtml index 1c8f32d..067d61c 100644 --- a/view/frontend/templates/speculation-rules.phtml +++ b/view/frontend/templates/speculation-rules.phtml @@ -12,9 +12,17 @@ use MageOS\ThemeOptimization\ViewModel\SpeculationRules; /** @var SpeculationRules $viewModel */ $viewModel = $block->getViewModel(); ?> -renderTag( +renderTag( 'script', ['type' => 'speculationrules'], $viewModel->getSpeculationRulesJson(), false ) ?> +getPrerenderingScript()): ?> + renderTag( + 'script', + ['type' => 'text/javascript'], + $prerenderingScript, + false + ) ?> + From 72daa7c8622a77596bed40efdc31132f6026141c Mon Sep 17 00:00:00 2001 From: JaJuMa Date: Thu, 16 Oct 2025 12:51:34 +0700 Subject: [PATCH 2/4] feat: add reload action script when page prerendering for hyva theme --- ViewModel/SpeculationRules.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/ViewModel/SpeculationRules.php b/ViewModel/SpeculationRules.php index e3230af..d77d7ab 100644 --- a/ViewModel/SpeculationRules.php +++ b/ViewModel/SpeculationRules.php @@ -6,6 +6,7 @@ use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\UrlInterface; use Magento\Framework\View\Element\Block\ArgumentInterface; +use Magento\Framework\View\DesignInterface; use Magento\Store\Model\ScopeInterface; class SpeculationRules implements ArgumentInterface @@ -20,6 +21,7 @@ public function __construct( protected ScopeConfigInterface $scopeConfig, protected UrlInterface $urlBuilder, protected SerializerInterface $serializer, + protected DesignInterface $viewDesign ) { } @@ -64,6 +66,7 @@ public function isPrerenderMode(): bool /** * Get prerendering change script for customer data reinitialization * Returns script only when prerender mode is enabled + * Uses different approaches for Hyva vs Luma themes * * @return string */ @@ -73,11 +76,16 @@ public function getPrerenderingScript(): string return ''; } + // Hyva theme uses a custom event, Luma uses RequireJS + $reloadAction = $this->isHyva() + ? "window.dispatchEvent(new CustomEvent('reload-customer-section-data'));" + : "require('Magento_Customer/js/customer-data').init();"; + return << { if (document.prerendering) { document.addEventListener("prerenderingchange", () => { - require('Magento_Customer/js/customer-data').init(); + $reloadAction }, { once: true }); } })(); @@ -183,4 +191,21 @@ public function getExcludedSelectors(): array return $rules; } + + /** + * Check if current theme is Hyva or extends from Hyva + * + * @return bool + */ + private function isHyva(): bool + { + $theme = $this->viewDesign->getDesignTheme(); + while ($theme) { + if (strpos($theme->getCode(), 'Hyva/') === 0) { + return true; + } + $theme = $theme->getParentTheme(); + } + return false; + } } From ddfad5365c120dddda64c0e73d026329fbe84fd5 Mon Sep 17 00:00:00 2001 From: JaJuMa Date: Thu, 16 Oct 2025 13:01:12 +0700 Subject: [PATCH 3/4] feat: add DesignInterface mock to SpeculationRulesTest --- Test/Unit/ViewModel/SpeculationRulesTest.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Test/Unit/ViewModel/SpeculationRulesTest.php b/Test/Unit/ViewModel/SpeculationRulesTest.php index 39c70ef..e6d66b8 100644 --- a/Test/Unit/ViewModel/SpeculationRulesTest.php +++ b/Test/Unit/ViewModel/SpeculationRulesTest.php @@ -5,6 +5,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\UrlInterface; +use Magento\Framework\View\DesignInterface; use Magento\Framework\View\Element\Block\ArgumentInterface; use Magento\Store\Model\ScopeInterface; use MageOS\ThemeOptimization\ViewModel\SpeculationRules; @@ -27,6 +28,11 @@ class SpeculationRulesTest extends TestCase */ private $serializerMock; + /** + * @var DesignInterface + */ + private $viewDesignMock; + /** * @var SpeculationRules */ @@ -37,11 +43,13 @@ protected function setUp(): void $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); $this->urlBuilderMock = $this->createMock(UrlInterface::class); $this->serializerMock = $this->createMock(SerializerInterface::class); + $this->viewDesignMock = $this->createMock(DesignInterface::class); $this->speculationRules = new SpeculationRules( $this->scopeConfigMock, $this->urlBuilderMock, - $this->serializerMock + $this->serializerMock, + $this->viewDesignMock ); } From 6a2b5ef43488c32ac2905c09dfa549815ae546bb Mon Sep 17 00:00:00 2001 From: JaJuMa Date: Thu, 16 Oct 2025 13:47:05 +0700 Subject: [PATCH 4/4] feat: use standard Magento 2 RequireJS syntax for customer data reinitialization --- ViewModel/SpeculationRules.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ViewModel/SpeculationRules.php b/ViewModel/SpeculationRules.php index d77d7ab..29567da 100644 --- a/ViewModel/SpeculationRules.php +++ b/ViewModel/SpeculationRules.php @@ -79,7 +79,9 @@ public function getPrerenderingScript(): string // Hyva theme uses a custom event, Luma uses RequireJS $reloadAction = $this->isHyva() ? "window.dispatchEvent(new CustomEvent('reload-customer-section-data'));" - : "require('Magento_Customer/js/customer-data').init();"; + : "require(['Magento_Customer/js/customer-data'], customerData => { + customerData.init(); + });"; return << {