Assets (CSS, JavaScript, Media)

Introduction

The TYPO3 component responsible for rendering the HTML and adding assets to a TYPO3 frontend or backend page is called \TYPO3\CMS\Core\Page\PageRenderer .

The PageRenderer 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 PageRenderer in TYPO3. For configuration options via TypoScript (usually used for the main theme files), see the TypoScript Reference. In extensions, both directly using the PageRenderer as well as using the more convenient AssetCollector is possible.

Asset collector

With the \TYPO3\CMS\Core\Page\AssetCollector 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:asset.css> and <f:asset.script> 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\CMS\Core\SingletonInterface ). 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\AssetCollector

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 $identifier, string $source, array $attributes = [], array $options = [])
param $identifier

the identifier

param $source

URI to JavaScript file (allows EXT: syntax)

param $attributes

additional HTML <script> tag attributes, default: []

param $options

['priority' => true] means rendering before other tags, default: []

Returns
self
addInlineJavaScript ( string $identifier, string $source, array $attributes = [], array $options = [])
param $identifier

the identifier

param $source

JavaScript code

param $attributes

additional HTML <script> tag attributes, default: []

param $options

['priority' => true] means rendering before other tags, default: []

Returns
self
addStyleSheet ( string $identifier, string $source, array $attributes = [], array $options = [])
param $identifier

the identifier

param $source

URI to stylesheet file (allows EXT: syntax)

param $attributes

additional HTML <link> tag attributes, default: []

param $options

['priority' => true] means rendering before other tags, default: []

Returns
self
addInlineStyleSheet ( string $identifier, string $source, array $attributes = [], array $options = [])
param $identifier

the identifier

param $source

stylesheet code

param $attributes

additional HTML <link> tag attributes, default: []

param $options

['priority' => true] means rendering before other tags, default: []

Returns
self
addMedia ( string $fileName, array $additionalInformation)
param $fileName

the fileName

param $additionalInformation

One dimensional hash map (array with non-numerical keys) with scalar values

Returns
self
removeJavaScript ( string $identifier)
param $identifier

the identifier

Returns
self
removeInlineJavaScript ( string $identifier)
param $identifier

the identifier

Returns
self
removeStyleSheet ( string $identifier)
param $identifier

the identifier

Returns
self
removeInlineStyleSheet ( string $identifier)
param $identifier

the identifier

Returns
self
removeMedia ( string $identifier)
param $identifier

the identifier

Returns
self
getMedia ( )
Returns
array
getJavaScripts ( ?bool $priority = NULL)
param $priority

the priority, default: NULL

Returns
array
getInlineJavaScripts ( ?bool $priority = NULL)
param $priority

the priority, default: NULL

Returns
array
getStyleSheets ( ?bool $priority = NULL)
param $priority

the priority, default: NULL

Returns
array
getInlineStyleSheets ( ?bool $priority = NULL)
param $priority

the priority, default: NULL

Returns
array
hasJavaScript ( string $identifier)
param $identifier

the identifier

Returns
bool
hasInlineJavaScript ( string $identifier)
param $identifier

the identifier

Returns
bool
hasStyleSheet ( string $identifier)
param $identifier

the identifier

Returns
bool
hasInlineStyleSheet ( string $identifier)
param $identifier

the identifier

Returns
bool
hasMedia ( string $fileName)
param $fileName

the fileName

Returns
bool

ViewHelper

There are also two ViewHelpers, the f:asset.css and the f:asset.script ViewHelper which use the AssetCollector 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.includeJSLibs.forceOnTop
  • page.includeJSLibs
  • page.includeJS.forceOnTop
  • page.includeJS
  • AssetCollector::addJavaScript() with 'priority'
  • page.jsInline
  • AssetCollector::addInlineJavaScript() with 'priority'
  • </head>
  • page.includeJSFooterlibs.forceOnTop
  • page.includeJSFooterlibs
  • page.includeJSFooter.forceOnTop
  • page.includeJSFooter
  • AssetCollector::addJavaScript()
  • page.jsFooterInline
  • AssetCollector::addInlineJavaScript()

Examples

The AssetCollector can be injected in the constructor of a class via dependency injection and then used in methods:

EXT:my_extension/Classes/MyClass.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\MyClass;

use TYPO3\CMS\Core\Page\AssetCollector;

final class MyClass
{
    public function __construct(
        private readonly AssetCollector $assetCollector,
    ) {}

    public function doSomething()
    {
        // $this->assetCollector can now be used
        // see examples below
    }
}
Copied!

Add a JavaScript file to the collector with script attribute data-foo="bar":

EXT:my_extension/Classes/MyClass.php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['data-foo' => 'bar']
);
Copied!

Add a JavaScript file to the collector with script attribute data-foo="bar" and a priority which means rendering before other script tags:

EXT:my_extension/Classes/MyClass.php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['data-foo' => 'bar'],
    ['priority' => true]
);
Copied!

Add a JavaScript file to the collector with type="module" (by default, no type= is output for JavaScript):

EXT:my_extension/Classes/MyClass.php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['type' => 'module']
);
Copied!

Check if a JavaScript file with the given identifier exists:

EXT:my_extension/Classes/MyClass.php
if ($this->assetCollector->hasJavaScript($identifier)) {
    // result: true - JavaScript with identifier $identifier exists
} else {
    // result: false - JavaScript with identifier $identifier does not exist
}
Copied!

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 PageRenderer class can be injected into the class via dependency injection:

EXT:my_extension/Classes/MyClass.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\MyClass;

use TYPO3\CMS\Core\Page\PageRenderer;

final class MyClass
{
    public function __construct(
        private readonly PageRenderer $pageRenderer,
    ) {}

    public function doSomething()
    {
        // $this->pageRenderer can now be used
        // see examples below
    }
}
Copied!

The following methods can then be used:

  • $this->pageRenderer->addHeaderData($javaScriptCode)
  • $this->pageRenderer->addCssFile($file)
  • $this->pageRenderer->addCssInlineBlock($name, $cssCode)
  • $this->pageRenderer->addCssLibrary($file)
  • $this->pageRenderer->addJsFile($file)
  • $this->pageRenderer->addJsFooterFile($file)
  • $this->pageRenderer->addJsFooterLibrary($name, $file)
  • $this->pageRenderer->addJsFooterInlineCode($name, $javaScriptCode)
  • $this->pageRenderer->addJsInlineCode($name, $javaScriptCode)
  • $this->pageRenderer->addJsLibrary($name, $file)

Using the TypoScriptFrontendController

Changed in version 13.0

The property additionalHeaderData has been marked as internal and should not be used. Use AssetCollector->addJavaScript() instead (like described in the examples above).

Deprecated since version 13.4

$GLOBALS['TSFE']->additionalHeaderData[$name] = $javaScriptCode;
Copied!