Assets (CSS, JavaScript, Media)
Table of Contents
Introduction
The TYPO3 component responsible for rendering the HTML and adding assets to a
TYPO3 frontend or backend page is called \TYPO3\
.
The Page
collects all assets to be rendered, takes care of
options such as concatenation or compression and finally generates the necessary
tags.
There are multiple ways to add assets to the Page
in TYPO3.
For configuration options via TypoScript (usually used for the main theme files),
see the TypoScript Reference. In
extensions, both directly using the Page
as well as using the
more convenient Asset
is possible.
Note
The Asset
is available since TYPO3 v10.3.
Asset collector
With the \TYPO3\
class, CSS and JavaScript
code (inline or external) can be added multiple times, but rendered only once in
the output. The class may be used directly in PHP code or the assets can be
added via the <f:
and <f:
ViewHelpers.
The priority
flag (default: false
) controls where the asset is
inserted:
- JavaScript will be output inside
<head>
if$priority == true
, or at the bottom of the<body>
tag if$priority == false
. - CSS will always be output inside
<head>
, yet grouped by$priority
.
The asset collector helps to work with content elements as components, effectively reducing the CSS to be loaded. It takes advantage of HTTP/2, which removes the necessity to concatenate all files in one file.
The asset collector class is implemented as a singleton
(\TYPO3\
). It replaces various other existing
options in TypoScript and methods in PHP for
inserting JavaScript and CSS code.
The asset collector also collects information about images on a page, which can be used in cached and non-cached components.
The API
- class AssetCollector
-
- Fully qualified name
-
\TYPO3\
CMS\ Core\ Page\ Asset Collector
The Asset Collector is responsible for keeping track of - everything within <script> tags: javascript files and inline javascript code - inline CSS and CSS files
The goal of the asset collector is to: - utilize a single "runtime-based" store for adding assets of certain kinds that are added to the output - allow to deal with assets from non-cacheable plugins and cacheable content in the Frontend - reduce the "power" and flexibility (I'd say it's a burden) of the "god class" PageRenderer. - reduce the burden of storing everything in PageRenderer
As a side-effect this allows to: - Add a single CSS snippet or CSS file per content block, but assure that the CSS is only added once to the output.
Note on the implementation: - We use a Singleton to make use of the AssetCollector throughout Frontend process (similar to PageRenderer). - Although this is not optimal, I don't see any other way to do so in the current code.
- addJavaScript ( string $source, array $attributes, array $options)
-
- param string $source
-
URI to JavaScript file (allows EXT: syntax)
- param array $attributes
-
additional HTML <script> tag attributes
- param array $options
-
['priority' => true] means rendering before other tags
- returntype
-
self
- addInlineJavaScript ( string $source, array $attributes, array $options)
-
- param string $source
-
JavaScript code
- param array $attributes
-
additional HTML <script> tag attributes
- param array $options
-
['priority' => true] means rendering before other tags
- returntype
-
self
- addStyleSheet ( string $source, array $attributes, array $options)
-
- param string $source
-
URI to stylesheet file (allows EXT: syntax)
- param array $attributes
-
additional HTML <link> tag attributes
- param array $options
-
['priority' => true] means rendering before other tags
- returntype
-
self
- addInlineStyleSheet ( string $source, array $attributes, array $options)
-
- param string $source
-
stylesheet code
- param array $attributes
-
additional HTML <link> tag attributes
- param array $options
-
['priority' => true] means rendering before other tags
- returntype
-
self
- addMedia ( array $additionalInformation)
-
- param array $additionalInformation
-
One dimensional hash map (array with non numerical keys) with scalar values
- returntype
-
self
- getJavaScripts ( bool priority = NULL)
-
- param bool $priority
-
the priority, default: NULL
- returntype
-
array
- getInlineJavaScripts ( bool priority = NULL)
-
- param bool $priority
-
the priority, default: NULL
- returntype
-
array
- getStyleSheets ( bool priority = NULL)
-
- param bool $priority
-
the priority, default: NULL
- returntype
-
array
Note
If the same asset is registered multiple times using different attributes or
options, both sets are merged. If the same attributes or options are given
with different values, the most recently registered ones overwrite the
existing ones. The has
methods can be used to check if an asset
exists before generating it again, hence avoiding redundancy.
Viewhelper
There are also two ViewHelpers, the
f:asset.css and the
f:asset.script ViewHelper which
use the Asset
API.
Rendering order
Currently, CSS and JavaScript registered with the asset collector will be rendered after their page renderer counterparts. The order is:
<head>
page.
include JSLibs. force On Top page.
include JSLibs page.
include JS. force On Top page.
include JS Asset
with 'priority'Collector:: add Java Script () page.
js Inline Asset
with 'priority'Collector:: add Inline Java Script () </
head> page.
include JSFooterlibs. force On Top page.
include JSFooterlibs page.
include JSFooter. force On Top page.
include JSFooter Asset
Collector:: add Java Script () page.
js Footer Inline Asset
Collector:: add Inline Java Script ()
Note
JavaScript registered with the asset collector is not affected by config.moveJsFromHeaderToFooter.
Examples
The Asset
can be injected in the constructor of a class via
dependency injection and then used in methods:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\MyClass;
use TYPO3\CMS\Core\Page\AssetCollector;
final class MyClass
{
private AssetCollector $assetCollector;
public function __construct(AssetCollector $assetCollector)
{
$this->assetCollector = $assetCollector;
}
public function doSomething()
{
// $this->assetCollector can now be used
// see examples below
}
}
Add a JavaScript file to the collector with script attribute
data-
:
$this->assetCollector->addJavaScript(
'my_ext_foo',
'EXT:my_extension/Resources/Public/JavaScript/foo.js',
['data-foo' => 'bar']
);
Add a JavaScript file to the collector with script attribute
data-
and a priority which means rendering before other script
tags:
$this->assetCollector->addJavaScript(
'my_ext_foo',
'EXT:my_extension/Resources/Public/JavaScript/foo.js',
['data-foo' => 'bar'],
['priority' => true]
);
Add a JavaScript file to the collector with type="module"
(by default,
no type=
is output for JavaScript):
$this->assetCollector->addJavaScript(
'my_ext_foo',
'EXT:my_extension/Resources/Public/JavaScript/foo.js',
['type' => 'module']
);
Check if a JavaScript file with the given identifier exists:
if ($this->assetCollector->hasJavaScript($identifier)) {
// result: true - JavaScript with identifier $identifier exists
} else {
// result: false - JavaScript with identifier $identifier does not exist
}
Events
There are two events available that allow additional adjusting of assets:
Former methods to add assets
Using the page renderer
An instance of the Page
class can be injected into the
class via dependency injection:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\MyClass;
use TYPO3\CMS\Core\Page\PageRenderer;
final class MyClass
{
private PageRenderer $pageRenderer;
public function __construct(PageRenderer $pageRenderer)
{
$this->pageRenderer = $pageRenderer;
}
public function doSomething()
{
// $this->pageRenderer can now be used
// see examples below
}
}
The following methods can then be used:
$this->page
Renderer->add Header Data ($java Script Code) $this->page
Renderer->add Css File ($file) $this->page
Renderer->add Css Inline Block ($name, $css Code) $this->page
Renderer->add Css Library ($file) $this->page
Renderer->add Js File ($file) $this->page
Renderer->add Js Footer File ($file) $this->page
Renderer->add Js Footer Library ($name, $file) $this->page
Renderer->add Js Footer Inline Code ($name, $java Script Code) $this->page
Renderer->add Js Inline Code ($name, $java Script Code) $this->page
Renderer->add Js Library ($name, $file)
Using the TypoScriptFrontendController
$GLOBALS['TSFE']->additionalHeaderData[$name] = $javaScriptCode;
Tip
Instead of using the global variable for retrieving the
Typo
you should consider to use the
PSR-7 request attribute
frontend.controller
wherever possible.