Skip to content
Snippets Groups Projects
Commit 09576ce7 authored by Rune Piper's avatar Rune Piper Committed by Christian Kuhn
Browse files

[FEATURE] Load merged JS files asynchronous

The async attribute is now assigned to the script tag of the concatenated
JS files if all files have the async attribute enabled in TypoScript.

Resolves: #83476
Releases: master
Change-Id: If4d5f03cac5920cf0bcccefb2e91cc229f9b9e77
Reviewed-on: https://review.typo3.org/57130


Reviewed-by: default avatarSascha Egerer <sascha@sascha-egerer.de>
Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: default avatarWouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 00439ea6
No related branches found
No related tags found
No related merge requests found
......@@ -169,6 +169,8 @@ class ResourceCompressor
*/
public function concatenateJsFiles(array $jsFiles)
{
$concatenatedJsFileIsAsync = false;
$allFilesToConcatenateAreAsync = true;
$filesToInclude = [];
foreach ($jsFiles as $key => $fileOptions) {
// invalid section found or no concatenation allowed, so continue
......@@ -184,6 +186,11 @@ class ResourceCompressor
} else {
$filesToInclude[$fileOptions['section']][] = $filenameFromMainDir;
}
if (!empty($fileOptions['async']) && (bool)$fileOptions['async']) {
$concatenatedJsFileIsAsync = true;
} else {
$allFilesToConcatenateAreAsync = false;
}
// remove the file from the incoming file array
unset($jsFiles[$key]);
}
......@@ -197,7 +204,8 @@ class ResourceCompressor
'compress' => true,
'excludeFromConcatenation' => true,
'forceOnTop' => false,
'allWrap' => ''
'allWrap' => '',
'async' => $concatenatedJsFileIsAsync && $allFilesToConcatenateAreAsync,
];
// place the merged javascript on top of the JS files
$jsFiles = array_merge([$targetFile => $concatenatedOptions], $jsFiles);
......
.. include:: ../../Includes.txt
===================================================
Feature: #83476 - Load merged JS files asynchronous
===================================================
See :issue:`83476`
Description
===========
The async attribute is now assigned to the script tag of the concatenated JS files if all files have the async attribute enabled in TypoScript.
Example:
--------
.. code-block:: typoscript
config.concatenateJs = 1
page = PAGE
page.includeJSFooter {
test = fileadmin/user_upload/test.js
test.async = 1
test2 = fileadmin/user_upload/test2.js
test2.async = 1
}
.. index:: Frontend, TypoScript, ext:core
......@@ -287,7 +287,7 @@ class ResourceCompressorTest extends BaseTestCase
/**
* @test
*/
public function concatenatedJsFileIsFlaggedToNotConcatenateAgain(): void
public function concatenateJsFileIsFlaggedToNotConcatenateAgain(): void
{
$fileName = 'fooFile.js';
$concatenatedFileName = 'merged_' . $fileName;
......@@ -309,6 +309,133 @@ class ResourceCompressorTest extends BaseTestCase
$this->assertTrue($result[$concatenatedFileName]['excludeFromConcatenation']);
}
/**
* @return array
*/
public function concatenateJsFileAsyncDataProvider(): array
{
return [
'all files have no async' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => false,
'section' => 'top',
],
],
false
],
'all files have async false' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => false,
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => false,
],
],
false
],
'all files have async true' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => true,
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => true,
],
],
true
],
'one file async true and one file async false' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => true,
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => false,
],
],
false
],
'one file async true and one file async false but is excluded form concatenation' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => true,
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => true,
'section' => 'top',
'async' => false,
],
],
true
],
'one file async false and one file async true but is excluded form concatenation' => [
[
[
'file' => 'file1.js',
'excludeFromConcatenation' => false,
'section' => 'top',
'async' => false,
],
[
'file' => 'file2.js',
'excludeFromConcatenation' => true,
'section' => 'top',
'async' => true,
],
],
false
],
];
}
/**
* @test
* @dataProvider concatenateJsFileAsyncDataProvider
* @param string $input
* @param bool $expected
*/
public function concatenateJsFileAddsAsyncPropertyIfAllFilesAreAsync(array $input, bool $expected): void
{
$concatenatedFileName = 'merged_foo.js';
$this->subject->expects($this->once())
->method('createMergedJsFile')
->will($this->returnValue($concatenatedFileName));
$result = $this->subject->concatenateJsFiles($input);
$this->assertSame($expected, $result[$concatenatedFileName]['async']);
}
/**
* @return array
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment