Skip to content

Commit 5b0ca91

Browse files
authored
feat: add prerender mode support and corresponding script for custome… (#24)
* feat: add prerender mode support and corresponding script for customer data reinitialization * feat: add reload action script when page prerendering for hyva theme * feat: add DesignInterface mock to SpeculationRulesTest * feat: use standard Magento 2 RequireJS syntax for customer data reinitialization
1 parent 41e6c94 commit 5b0ca91

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

Test/Unit/ViewModel/SpeculationRulesTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Magento\Framework\App\Config\ScopeConfigInterface;
66
use Magento\Framework\Serialize\SerializerInterface;
77
use Magento\Framework\UrlInterface;
8+
use Magento\Framework\View\DesignInterface;
89
use Magento\Framework\View\Element\Block\ArgumentInterface;
910
use Magento\Store\Model\ScopeInterface;
1011
use MageOS\ThemeOptimization\ViewModel\SpeculationRules;
@@ -27,6 +28,11 @@ class SpeculationRulesTest extends TestCase
2728
*/
2829
private $serializerMock;
2930

31+
/**
32+
* @var DesignInterface
33+
*/
34+
private $viewDesignMock;
35+
3036
/**
3137
* @var SpeculationRules
3238
*/
@@ -37,11 +43,13 @@ protected function setUp(): void
3743
$this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class);
3844
$this->urlBuilderMock = $this->createMock(UrlInterface::class);
3945
$this->serializerMock = $this->createMock(SerializerInterface::class);
46+
$this->viewDesignMock = $this->createMock(DesignInterface::class);
4047

4148
$this->speculationRules = new SpeculationRules(
4249
$this->scopeConfigMock,
4350
$this->urlBuilderMock,
44-
$this->serializerMock
51+
$this->serializerMock,
52+
$this->viewDesignMock
4553
);
4654
}
4755

ViewModel/SpeculationRules.php

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@
66
use Magento\Framework\Serialize\SerializerInterface;
77
use Magento\Framework\UrlInterface;
88
use Magento\Framework\View\Element\Block\ArgumentInterface;
9+
use Magento\Framework\View\DesignInterface;
910
use Magento\Store\Model\ScopeInterface;
1011

1112
class SpeculationRules implements ArgumentInterface
1213
{
1314
protected const CONFIG_PATH = 'system/speculation_rules/';
14-
protected const FETCH_MODES = ['prefetch', 'prerender'];
15+
protected const MODE_PREFETCH = 'prefetch';
16+
protected const MODE_PRERENDER = 'prerender';
17+
protected const FETCH_MODES = [self::MODE_PREFETCH, self::MODE_PRERENDER];
1518
protected const EAGERNESS_MODES = ['conservative', 'moderate', 'eager'];
1619

1720
public function __construct(
1821
protected ScopeConfigInterface $scopeConfig,
1922
protected UrlInterface $urlBuilder,
2023
protected SerializerInterface $serializer,
24+
protected DesignInterface $viewDesign
2125
)
2226
{
2327
}
@@ -35,7 +39,7 @@ public function getMode(): string
3539
return $mode;
3640
}
3741

38-
return 'prefetch';
42+
return self::MODE_PREFETCH;
3943
}
4044

4145
public function getEagerness(): string
@@ -49,6 +53,47 @@ public function getEagerness(): string
4953
return 'moderate';
5054
}
5155

56+
/**
57+
* Check if the current mode is prerender
58+
*
59+
* @return bool
60+
*/
61+
public function isPrerenderMode(): bool
62+
{
63+
return $this->getMode() === self::MODE_PRERENDER;
64+
}
65+
66+
/**
67+
* Get prerendering change script for customer data reinitialization
68+
* Returns script only when prerender mode is enabled
69+
* Uses different approaches for Hyva vs Luma themes
70+
*
71+
* @return string
72+
*/
73+
public function getPrerenderingScript(): string
74+
{
75+
if (!$this->isPrerenderMode()) {
76+
return '';
77+
}
78+
79+
// Hyva theme uses a custom event, Luma uses RequireJS
80+
$reloadAction = $this->isHyva()
81+
? "window.dispatchEvent(new CustomEvent('reload-customer-section-data'));"
82+
: "require(['Magento_Customer/js/customer-data'], customerData => {
83+
customerData.init();
84+
});";
85+
86+
return <<<JS
87+
(() => {
88+
if (document.prerendering) {
89+
document.addEventListener("prerenderingchange", () => {
90+
$reloadAction
91+
}, { once: true });
92+
}
93+
})();
94+
JS;
95+
}
96+
5297
public function getSpeculationRules(): array
5398
{
5499
// Possible future development: add support for multiple modes and rulesets at once.
@@ -148,4 +193,21 @@ public function getExcludedSelectors(): array
148193

149194
return $rules;
150195
}
196+
197+
/**
198+
* Check if current theme is Hyva or extends from Hyva
199+
*
200+
* @return bool
201+
*/
202+
private function isHyva(): bool
203+
{
204+
$theme = $this->viewDesign->getDesignTheme();
205+
while ($theme) {
206+
if (strpos($theme->getCode(), 'Hyva/') === 0) {
207+
return true;
208+
}
209+
$theme = $theme->getParentTheme();
210+
}
211+
return false;
212+
}
151213
}

view/frontend/templates/speculation-rules.phtml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@ use MageOS\ThemeOptimization\ViewModel\SpeculationRules;
1212
/** @var SpeculationRules $viewModel */
1313
$viewModel = $block->getViewModel();
1414
?>
15-
<?= $secureRenderer->renderTag(
15+
<?= /* @noEscape */ $secureRenderer->renderTag(
1616
'script',
1717
['type' => 'speculationrules'],
1818
$viewModel->getSpeculationRulesJson(),
1919
false
2020
) ?>
21+
<?php if ($prerenderingScript = $viewModel->getPrerenderingScript()): ?>
22+
<?= /* @noEscape */ $secureRenderer->renderTag(
23+
'script',
24+
['type' => 'text/javascript'],
25+
$prerenderingScript,
26+
false
27+
) ?>
28+
<?php endif; ?>

0 commit comments

Comments
 (0)