Skip to content

Commit 06b38ce

Browse files
committed
Refactor ReactInjectPlugin to include MsApplicationTileImage as a nullable parameter in the constructor. Introduce a new Gallery block for product images with image preloading functionality. Update README.md with JavaScript optimization configuration details and add support for base64 image encoding in product configuration. Enhance tests with shared mock classes to streamline testing process.
1 parent cc9aa64 commit 06b38ce

16 files changed

Lines changed: 805 additions & 96 deletions

File tree

Block/Product/View/Gallery.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace React\React\Block\Product\View;
4+
5+
use Magento\Catalog\Block\Product\View\Gallery as MagentoGallery;
6+
use React\React\Features\ImagePreload;
7+
8+
class Gallery extends MagentoGallery
9+
{
10+
/**
11+
* @var ImagePreload
12+
*/
13+
protected $imagePreload;
14+
15+
/**
16+
* @param \Magento\Catalog\Block\Product\Context $context
17+
* @param \Magento\Framework\Stdlib\ArrayUtils $arrayUtils
18+
* @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
19+
* @param ImagePreload $imagePreload
20+
* @param array $data
21+
* @param \Magento\Catalog\Model\Product\Image\UrlBuilder|null $urlBuilder
22+
*/
23+
public function __construct(
24+
\Magento\Catalog\Block\Product\Context $context,
25+
\Magento\Framework\Stdlib\ArrayUtils $arrayUtils,
26+
\Magento\Framework\Json\EncoderInterface $jsonEncoder,
27+
ImagePreload $imagePreload,
28+
array $data = [],
29+
\Magento\Catalog\Model\Product\Image\UrlBuilder $urlBuilder = null
30+
) {
31+
$this->imagePreload = $imagePreload;
32+
parent::__construct($context, $arrayUtils, $jsonEncoder, $data, null, [], $urlBuilder);
33+
}
34+
35+
/**
36+
* Preload mobile hero image using HTTP Link header
37+
*
38+
* @param string $imageUrl The URL of the image to preload
39+
* @param bool $isBase64 Whether the image is base64 encoded
40+
* @return void
41+
*/
42+
public function preloadMobileImage($imageUrl, $isBase64 = false)
43+
{
44+
if (!$isBase64 && !empty($imageUrl) && !headers_sent()) {
45+
// Use PHP header() function directly to avoid Magento code generation issues
46+
header("Link: <" . $imageUrl . ">; rel=preload; as=image; fetchpriority=high", false);
47+
}
48+
}
49+
50+
/**
51+
* Check if base64 image encoding is enabled
52+
*
53+
* @return bool
54+
*/
55+
public function isBase64ImageEnabled()
56+
{
57+
return $this->_scopeConfig->isSetFlag(
58+
'react_vue_config/product/base64_image',
59+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
60+
);
61+
}
62+
}

Features/ImagePreload.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace React\React\Features;
4+
5+
class ImagePreload
6+
{
7+
/**
8+
* Preload image using HTTP Link header
9+
*
10+
* @param string $imageUrl The URL of the image to preload
11+
* @param bool $isBase64 Whether the image is base64 encoded (skip preload if true)
12+
* @param string $fetchpriority Priority level: 'high', 'low', or 'auto' (default: 'high')
13+
* @return void
14+
*/
15+
public function preloadImage($imageUrl, $isBase64 = false, $fetchpriority = 'high')
16+
{
17+
if (!$isBase64 && !empty($imageUrl)) {
18+
// Use @header() with false parameter to allow setting header even after headers started
19+
// This matches the pattern used in ReactInjectPlugin.php
20+
@header("Link: <" . $imageUrl . ">; rel=preload; as=image; fetchpriority=" . $fetchpriority, false);
21+
}
22+
}
23+
24+
/**
25+
* Preload multiple images using HTTP Link header
26+
*
27+
* @param array $imageUrls Array of image URLs to preload
28+
* @param bool $isBase64 Whether the images are base64 encoded (skip preload if true)
29+
* @param string $fetchpriority Priority level: 'high', 'low', or 'auto' (default: 'high')
30+
* @return void
31+
*/
32+
public function preloadImages(array $imageUrls, $isBase64 = false, $fetchpriority = 'high')
33+
{
34+
if ($isBase64 || headers_sent() || empty($imageUrls)) {
35+
return;
36+
}
37+
38+
$links = [];
39+
foreach ($imageUrls as $imageUrl) {
40+
if (!empty($imageUrl)) {
41+
$links[] = "<" . $imageUrl . ">; rel=preload; as=image; fetchpriority=" . $fetchpriority;
42+
}
43+
}
44+
45+
if (!empty($links)) {
46+
header("Link: " . implode(", ", $links));
47+
}
48+
}
49+
}

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,86 @@ php bin/magento config:set dev/js/move_script_to_bottom 1
3636

3737
![React + Magento 2](https://github.com/Genaker/reactmagento2/blob/master/KnockoutMagento2React.png)
3838

39+
## JavaScript Optimization Configuration
40+
41+
To optimize JavaScript performance with existing Magento JS no JS changes needed!!, configure the following settings:
42+
43+
**Important:** This module uses native Magento JavaScript methods and APIs. No custom JavaScript modifications are required - all optimizations work with Magento's existing JavaScript implementation out of the box. The module leverages Magento's built-in JavaScript functionality (`requirejs`, `mage/requirejs/mixins.js`, `requirejs-config.js`, etc.) without replacing or modifying core Magento JS files. The module leverages Magento's built-in JavaScript functionality (`requirejs`, `mage/requirejs/mixins.js`, `requirejs-config.js`, etc.) without replacing or modifying core Magento JS files.
44+
45+
### 1. Move JS to Bottom (Defer JS)
46+
Enable the module's "Defer JS" feature to move JavaScript files to the bottom of the page for better performance. Scripts with `no-defer` attribute are preserved in their original position.
47+
48+
**Via Admin Panel:**
49+
- Go to: Stores > Configuration > React-Luma integration > Configuration > Magento JS configuration
50+
- Set "Defer JS (Move Scripts to Bottom)" to "Yes"
51+
- Save config and clear cache
52+
53+
**Via CLI:**
54+
```bash
55+
php bin/magento config:set react_vue_config/junk/defer_js 1
56+
php bin/magento cache:clean
57+
```
58+
59+
**Via GET Parameter (for testing):**
60+
- Add `?defer-js=true` to any URL to enable temporarily
61+
- Add `?defer-js=false` to disable temporarily
62+
63+
### 2. Disable JavaScript Bundling (!Important)
64+
**Important:** Disable Magento's JavaScript bundling to prevent conflicts and ensure proper script loading order.
65+
66+
**Why disable bundling?**
67+
Magento's JavaScript bundling or any other MAgento bundlings creates large combined JavaScript files that block page rendering and increase blocking time. When bundling is enabled:
68+
- Multiple JavaScript files are combined into large bundles that must be downloaded and parsed before the page can become interactive
69+
- This increases **Total Blocking Time (TBT)** and delays **Time to Interactive (TTI)**
70+
- Large bundles prevent parallel script loading and caching optimization
71+
- Scripts that could load asynchronously are forced to load synchronously in the bundle
72+
- Individual script updates require re-downloading the entire bundle
73+
74+
By disabling bundling:
75+
- Scripts can load in parallel, reducing blocking time
76+
- Individual scripts can be cached independently
77+
- Smaller files load faster and parse quicker
78+
- Better browser caching - only changed scripts need to be re-downloaded
79+
- Improved performance metrics (LCP, FCP, TBT, TTI)
80+
81+
**Note:** Never use Magento JavaScript bundling - it doesn't have a positive influence on Core Web Vitals and actually degrades performance metrics.
82+
83+
**Via CLI:**
84+
```bash
85+
php bin/magento config:set dev/js/enable_js_bundling 0
86+
php bin/magento cache:clean
87+
```
88+
89+
**Via Admin Panel:**
90+
- Go to: Stores > Configuration > Advanced > Developer > JavaScript Settings
91+
- Set "Enable JavaScript Bundling" to "No"
92+
- Save config and clear cache
93+
94+
### 3. Enable JavaScript Minification
95+
Enable JavaScript minification to reduce file sizes and improve page load times.
96+
97+
**Via CLI:**
98+
```bash
99+
php bin/magento config:set dev/js/minify_files 1
100+
php bin/magento cache:clean
101+
```
102+
103+
**Via Admin Panel:**
104+
- Go to: Stores > Configuration > Advanced > Developer > JavaScript Settings
105+
- Set "Minify JavaScript Files" to "Yes"
106+
- Save config and clear cache
107+
108+
**Note:** In production mode, the Developer section may be hidden in the Admin Panel. Use CLI commands instead.
109+
110+
### Complete JavaScript Optimization Setup
111+
Run all three commands together for optimal JavaScript performance:
112+
```bash
113+
php bin/magento config:set react_vue_config/junk/defer_js 1
114+
php bin/magento config:set dev/js/enable_js_bundling 0
115+
php bin/magento config:set dev/js/minify_files 1
116+
php bin/magento cache:clean
117+
```
118+
39119
# Updates:
40120
- VueJS implementation
41121
- Magento Configuration enable React, VueJS

ReactInjectPlugin.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ class ReactInjectPlugin extends Renderer
4848
* @param \Magento\Framework\Escaper $escaper
4949
* @param \Magento\Framework\Stdlib\StringUtils $string
5050
* @param \Psr\Log\LoggerInterface $logger
51-
* @param MsApplicationTileImage|null $msApplicationTileImage
5251
* @param ScopeConfigInterface $config
5352
* @param State $state
5453
* @param StoreManagerInterface $store
5554
* @param Template $template
55+
* @param MsApplicationTileImage|null $msApplicationTileImage
5656
*/
5757
public function __construct(
5858
Config $pageConfig,
@@ -61,11 +61,11 @@ public function __construct(
6161
\Magento\Framework\Escaper $escaper,
6262
\Magento\Framework\Stdlib\StringUtils $string,
6363
\Psr\Log\LoggerInterface $logger,
64-
MsApplicationTileImage $msApplicationTileImage = null,
6564
private ScopeConfigInterface $config,
6665
private State $state,
6766
private StoreManagerInterface $store,
68-
private Template $template
67+
private Template $template,
68+
?MsApplicationTileImage $msApplicationTileImage = null
6969
) {
7070
parent::__construct($pageConfig, $assetMergeService, $urlBuilder, $escaper, $string, $logger, $msApplicationTileImage);
7171
$this->configuration = $this->getConfigurationSettings();

etc/adminhtml/system.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@
6565
<config_path>react_vue_config/css/defer_css</config_path>
6666
</field>
6767
</group>
68+
<group id="product" sortOrder="20" showInWebsite="1" showInStore="1" showInDefault="1" translate="label">
69+
<label>Product configuration</label>
70+
<field id="base64_image" type="select" sortOrder="10" showInWebsite="1" showInStore="1" showInDefault="1" translate="label">
71+
<label>Enable Base64 Image Encoding</label>
72+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
73+
<comment>Convert mobile product images to base64 format. Can improve LCP by 0.1-0.2s but increases HTML size.</comment>
74+
</field>
75+
</group>
6876
</section>
6977
</system>
7078
</config>

etc/config.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
<critical>1</critical>
2121
<defer_css>1</defer_css>
2222
</css>
23+
<product>
24+
<base64_image>1</base64_image>
25+
</product>
2326
</react_vue_config>
2427
</default>
2528
</config>

etc/di.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<preference for="Magento\Framework\View\Page\Config\Renderer" type="React\React\ReactInjectPlugin"/>
55
<preference for="Magento\Swatches\Block\Product\Renderer\Configurable" type="React\React\Block\Product\Renderer\Configurable"/>
66
<preference for="Magento\Catalog\Block\Product\ImageFactory" type="React\React\Block\Product\ImageFactory"/>
7-
87
<preference for="Magento\Checkout\CustomerData\Cart" type="React\React\CustomerData\Cart" />
98

109
<type name="Magento\Framework\App\Response\HttpInterface">

tests/Pest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
use Pest\TestSuite;
44

5+
// Load shared mock classes
6+
require_once __DIR__ . '/Unit/Mocks.php';
7+
58
/*
69
|--------------------------------------------------------------------------
710
| Test Case

0 commit comments

Comments
 (0)