diff --git a/README.md b/README.md index 8e78e2f..172480f 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,9 @@ $ bin/magento setup:upgrade --keep-generated In `System > Configuration > Advanced > Developer > JavaScript Settings` two configuration settings can be seen. One of them is the regular expression used for the `async` HTML attribute, the other for `defer`. +There is also an other setting, the `Check block scripts for "async" and "defer"` which defaults to "No", and can be +enabled when there is also a need to apply `async` and `defer` to scripts inside blocks. + ![Configuration Settings](adjs-configuration.png) + +The following regex can be used to match all scripts accept the require.js: `^((?!require.js).)*$` diff --git a/adjs-configuration.png b/adjs-configuration.png index e4c00dc..140bdfe 100644 Binary files a/adjs-configuration.png and b/adjs-configuration.png differ diff --git a/composer.json b/composer.json index 5fe3452..e79321d 100644 --- a/composer.json +++ b/composer.json @@ -2,16 +2,21 @@ "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.1.0", "license": "MIT", "authors": [ { "email": "julian@weprovide.com", "name": "Julian van den Berkmortel" + }, + { + "email": "sander.merks@iodigital.com", + "name": "Sander Merks" } ], "require": { "magento/framework": "~103.0.0", - "phpgt/dom": "2.1.6", + "phpgt/dom": "2.1.6||2.2.3", "ext-libxml": "*" }, "autoload": { diff --git a/src/Plugin/AddAsyncDeferToBlockScripts.php b/src/Plugin/AddAsyncDeferToBlockScripts.php new file mode 100644 index 0000000..0494b54 --- /dev/null +++ b/src/Plugin/AddAsyncDeferToBlockScripts.php @@ -0,0 +1,46 @@ +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; + } +} diff --git a/src/Plugin/AddAsyncDeferToPageAssets.php b/src/Plugin/AddAsyncDeferToPageAssets.php index 65b8bba..78c7912 100644 --- a/src/Plugin/AddAsyncDeferToPageAssets.php +++ b/src/Plugin/AddAsyncDeferToPageAssets.php @@ -4,113 +4,34 @@ namespace WeProvide\AsyncDeferJs\Plugin; use Magento\Framework\View\Page\Config\Renderer; -use Psr\Log\LoggerInterface; -use WeProvide\AsyncDeferJs\Config\AsyncRegexValueReader; -use WeProvide\AsyncDeferJs\Config\DeferRegexValueReader; -use WeProvide\AsyncDeferJs\Config\ValueReaderInterface; -use WeProvide\AsyncDeferJs\Exception\Config\ValueReaderException; -use WeProvide\AsyncDeferJs\Factory\HTMLDocumentFactory; +use WeProvide\AsyncDeferJs\Service\ScriptAdjuster; /** - * Responsible for adding the "async" and "defer" attribute to HTML script elements that match a set of regular expressions + * Responsible for adding the "async" and "defer" attribute to HTML script elements that match a set of regular + * expressions */ class AddAsyncDeferToPageAssets { - /** @var HTMLDocumentFactory */ - protected $htmlDocumentFactory; - - /** @var ValueReaderInterface */ - protected $asyncRegexValueReader; - - /** @var ValueReaderInterface */ - protected $deferRegexValueReader; - - /** @var LoggerInterface */ - protected $logger; + /** @var ScriptAdjuster */ + protected ScriptAdjuster $scriptAdjuster; /** - * AddAsyncDeferToPageAssets constructor - * - * @param HTMLDocumentFactory $htmlDocumentFactory - * @param ValueReaderInterface $asyncRegexValueReader - * @param ValueReaderInterface $deferRegexValueReader - * @param LoggerInterface $logger + * @param ScriptAdjuster $scriptAdjuster */ - public function __construct( - HTMLDocumentFactory $htmlDocumentFactory, - ValueReaderInterface $asyncRegexValueReader, - ValueReaderInterface $deferRegexValueReader, - LoggerInterface $logger - ) { - $this->htmlDocumentFactory = $htmlDocumentFactory; - $this->asyncRegexValueReader = $asyncRegexValueReader; - $this->deferRegexValueReader = $deferRegexValueReader; - $this->logger = $logger; - } - - public function afterRenderAssets(Renderer $subject, string $result): string + public function __construct(ScriptAdjuster $scriptAdjuster) { - $document = $this->htmlDocumentFactory->create($result); - - foreach ($document->querySelectorAll('script') 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; - } + $this->scriptAdjuster = $scriptAdjuster; } /** - * Check if the given source matches the regular expression for adding the "defer" HTML attribute + * Gives the result to the script adjuster to apply async and defer * - * @param string $src the source to match - * @return bool true if the given source matches the regular expression, false otherwise + * @param Renderer $subject + * @param string $result + * @return string */ - protected function matchDeferRegex(string $src): bool + public function afterRenderAssets(Renderer $subject, string $result): string { - 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; - } + return $this->scriptAdjuster->adjustScripts($result); } } diff --git a/src/Service/Config.php b/src/Service/Config.php new file mode 100644 index 0000000..e95d497 --- /dev/null +++ b/src/Service/Config.php @@ -0,0 +1,38 @@ +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 + ); + } +} diff --git a/src/Service/ScriptAdjuster.php b/src/Service/ScriptAdjuster.php new file mode 100644 index 0000000..032015f --- /dev/null +++ b/src/Service/ScriptAdjuster.php @@ -0,0 +1,115 @@ +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; + } + } +} diff --git a/src/etc/adminhtml/system.xml b/src/etc/adminhtml/system.xml index 5139f91..417784f 100644 --- a/src/etc/adminhtml/system.xml +++ b/src/etc/adminhtml/system.xml @@ -3,6 +3,11 @@
+ + + Magento\Config\Model\Config\Source\Yesno + + If the source of a script matches this regular expression an "async" attribute will be added diff --git a/src/etc/di.xml b/src/etc/di.xml index ea5ec0a..093a16d 100644 --- a/src/etc/di.xml +++ b/src/etc/di.xml @@ -1,6 +1,6 @@ - + WeProvide\AsyncDeferJs\Config\AsyncRegexValueReader WeProvide\AsyncDeferJs\Config\DeferRegexValueReader diff --git a/src/etc/frontend/di.xml b/src/etc/frontend/di.xml index bcf1b8f..d1d4036 100644 --- a/src/etc/frontend/di.xml +++ b/src/etc/frontend/di.xml @@ -1,6 +1,13 @@ - + + + +