This repository has been archived by the owner on May 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from weprovide/feature/block_script_handling
Option added for adding async defer to scripts inside blocks
- Loading branch information
Showing
10 changed files
with
237 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,12 +2,16 @@ | |
"name": "weprovide/magento2-module-async-defer-js", | ||
"description": "A module which adds the \"async\" and \"defer\" HTML attributes to scripts", | ||
"type": "magento2-module", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"email": "[email protected]", | ||
"name": "Julian van den Berkmortel" | ||
}, | ||
{ | ||
"email": "[email protected]", | ||
"name": "Sander Merks" | ||
} | ||
], | ||
"require": { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace WeProvide\AsyncDeferJs\Plugin; | ||
|
||
use Magento\Framework\View\Element\AbstractBlock; | ||
use WeProvide\AsyncDeferJs\Service\Config as ConfigService; | ||
use WeProvide\AsyncDeferJs\Service\ScriptAdjuster; | ||
|
||
/** | ||
* Responsible for adding the "async" and "defer" attribute to HTML script elements that match a set of regular | ||
* expressions | ||
*/ | ||
class AddAsyncDeferToBlockScripts | ||
{ | ||
/** @var ScriptAdjuster */ | ||
protected ScriptAdjuster $scriptAdjuster; | ||
/** @var ConfigService */ | ||
protected ConfigService $configService; | ||
|
||
/** | ||
* @param ScriptAdjuster $scriptAdjuster | ||
* @param ConfigService $configService | ||
*/ | ||
public function __construct(ScriptAdjuster $scriptAdjuster, ConfigService $configService) | ||
{ | ||
$this->scriptAdjuster = $scriptAdjuster; | ||
$this->configService = $configService; | ||
} | ||
|
||
/** | ||
* Gives the result to the script adjuster to apply async and defer | ||
* | ||
* @param AbstractBlock $subject | ||
* @param string $result | ||
* @return string | ||
*/ | ||
public function afterToHtml(AbstractBlock $subject, string $result): string | ||
{ | ||
if ($this->configService->shouldCheckBlockScript()) { | ||
$result = $this->scriptAdjuster->adjustScripts($result); | ||
} | ||
|
||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace WeProvide\AsyncDeferJs\Service; | ||
|
||
use Magento\Framework\App\Config\ScopeConfigInterface; | ||
use Magento\Store\Model\ScopeInterface; | ||
|
||
class Config | ||
{ | ||
/** @var string */ | ||
protected const CONFIG_APPLY_TO_BLOCKS = 'dev/js/apply_async_defer_to_blocks'; | ||
|
||
/** @var ScopeConfigInterface */ | ||
protected ScopeConfigInterface $scopeConfig; | ||
|
||
/** | ||
* @param ScopeConfigInterface $scopeConfig | ||
*/ | ||
public function __construct(ScopeConfigInterface $scopeConfig) | ||
{ | ||
$this->scopeConfig = $scopeConfig; | ||
} | ||
|
||
/** | ||
* Whether blocks should be checked on scripts as well | ||
* | ||
* @return bool | ||
*/ | ||
public function shouldCheckBlockScript(): bool | ||
{ | ||
return $this->scopeConfig->isSetFlag( | ||
static::CONFIG_APPLY_TO_BLOCKS, | ||
ScopeInterface::SCOPE_STORE | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace WeProvide\AsyncDeferJs\Service; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use WeProvide\AsyncDeferJs\Config\ValueReaderInterface; | ||
use WeProvide\AsyncDeferJs\Exception\Config\ValueReaderException; | ||
use WeProvide\AsyncDeferJs\Factory\HTMLDocumentFactory; | ||
|
||
class ScriptAdjuster | ||
{ | ||
/** @var HTMLDocumentFactory */ | ||
protected HTMLDocumentFactory $htmlDocumentFactory; | ||
|
||
/** @var ValueReaderInterface */ | ||
protected ValueReaderInterface $asyncRegexValueReader; | ||
|
||
/** @var ValueReaderInterface */ | ||
protected ValueReaderInterface $deferRegexValueReader; | ||
|
||
/** @var LoggerInterface */ | ||
protected LoggerInterface $logger; | ||
|
||
/** | ||
* @param HTMLDocumentFactory $htmlDocumentFactory | ||
* @param ValueReaderInterface $asyncRegexValueReader | ||
* @param ValueReaderInterface $deferRegexValueReader | ||
* @param LoggerInterface $logger | ||
*/ | ||
public function __construct( | ||
HTMLDocumentFactory $htmlDocumentFactory, | ||
ValueReaderInterface $asyncRegexValueReader, | ||
ValueReaderInterface $deferRegexValueReader, | ||
LoggerInterface $logger | ||
) { | ||
$this->htmlDocumentFactory = $htmlDocumentFactory; | ||
$this->asyncRegexValueReader = $asyncRegexValueReader; | ||
$this->deferRegexValueReader = $deferRegexValueReader; | ||
$this->logger = $logger; | ||
} | ||
|
||
/** | ||
* Adds async and defer to the scripts inside the html when they match with the regex | ||
* | ||
* @param string $html | ||
* @return string | ||
*/ | ||
public function adjustScripts(string $html): string | ||
{ | ||
$document = $this->htmlDocumentFactory->create($html); | ||
|
||
foreach ($document->querySelectorAll('script[src]') as $script) { | ||
$src = $script->getAttribute('src'); | ||
|
||
if ($src === null) { | ||
continue; | ||
} | ||
|
||
if ($this->matchAsyncRegex($src)) { | ||
$script->setAttribute('async', 'true'); | ||
} | ||
|
||
if ($this->matchDeferRegex($src)) { | ||
$script->setAttribute('defer', 'true'); | ||
} | ||
} | ||
|
||
// https://stackoverflow.com/a/10023094/4391861 | ||
return preg_replace('~<(?:!DOCTYPE|/?(?:html|body|head))[^>]*>\s*~i', '', $document->saveHTML()); | ||
} | ||
|
||
/** | ||
* Check if the given source matches the regular expression for adding the "async" HTML attribute | ||
* | ||
* @param string $src the source to match | ||
* @return bool true if the given source matches the regular expression, false otherwise | ||
*/ | ||
protected function matchAsyncRegex(string $src): bool | ||
{ | ||
try { | ||
$regex = $this->asyncRegexValueReader->read(); | ||
return $regex !== null && preg_match($regex, $src) === 1; | ||
} catch (ValueReaderException $exception) { | ||
$this->logger->warning(sprintf( | ||
'Something went wrong whilst reading the regular expression for the "async" HTML attribute: %s', | ||
$exception->getMessage() | ||
)); | ||
|
||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Check if the given source matches the regular expression for adding the "defer" HTML attribute | ||
* | ||
* @param string $src the source to match | ||
* @return bool true if the given source matches the regular expression, false otherwise | ||
*/ | ||
protected function matchDeferRegex(string $src): bool | ||
{ | ||
try { | ||
$regex = $this->deferRegexValueReader->read(); | ||
return $regex !== null && preg_match($regex, $src) === 1; | ||
} catch (ValueReaderException $exception) { | ||
$this->logger->warning(sprintf( | ||
'Something went wrong whilst reading the regular expression for the "defer" HTML attribute: %s', | ||
$exception->getMessage() | ||
)); | ||
|
||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,13 @@ | ||
<?xml version="1.0"?> | ||
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> | ||
<type name="Magento\Framework\View\Page\Config\Renderer"> | ||
<plugin name="add_async_defer_to_page_assets" type="WeProvide\AsyncDeferJs\Plugin\AddAsyncDeferToPageAssets" /> | ||
<plugin name="add_async_defer_to_page_assets" | ||
type="WeProvide\AsyncDeferJs\Plugin\AddAsyncDeferToPageAssets" | ||
sortOrder="999"/> | ||
</type> | ||
<type name="Magento\Framework\View\Element\AbstractBlock"> | ||
<plugin name="add_async_defer_to_block_scripts" | ||
type="WeProvide\AsyncDeferJs\Plugin\AddAsyncDeferToBlockScripts" | ||
sortOrder="999"/> | ||
</type> | ||
</config> |