Web Assets: Difference between revisions
From Joomla! Documentation
Markup, spelling changes and some Words2Watch corrections. |
Phrasing, capitalization and markup changes. |
||
| Line 4: | Line 4: | ||
</translate> | </translate> | ||
<translate><!--T:115--> In the Frontend world many assets are related. For example our keepalive script depends on the core.js file for options management. In Joomla there never was an easy way to specify this; you just had to include multiple files. Joomla 4 changes this with the concept of web assets.</translate> | <translate><!--T:115--> In the Frontend world many assets are related. For example, our ''keepalive'' script depends on the ''core.js'' file for options management. In Joomla there never was an easy way to specify this; you just had to include multiple files. Joomla 4 changes this with the concept of web assets.</translate> | ||
<translate> | <translate> | ||
| Line 12: | Line 12: | ||
<translate><!--T:117--> Related assets are defined in a JSON file such as [https://github.com/joomla/joomla-cms/blob/7b72c565b610e02c1b01f8958d622879631fa6a2/build/media_source/system/joomla.asset.json#L14-L21 system/joomla.asset.json#L14-L21]</translate> | <translate><!--T:117--> Related assets are defined in a JSON file such as [https://github.com/joomla/joomla-cms/blob/7b72c565b610e02c1b01f8958d622879631fa6a2/build/media_source/system/joomla.asset.json#L14-L21 system/joomla.asset.json#L14-L21]</translate> | ||
<translate><!--T:118--> This has a structure of having a schema definition (for validation), name, version, license and then one or more asset definitions. Assets | <translate><!--T:118--> This has a structure of having a schema definition (for validation), name, version, license and then one or more asset definitions. Assets comprise a list of JavaScript files and CSS files related to the assets and any dependencies. The dependencies section is just a list of asset names that are required for the asset to function. Example:</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 57: | Line 57: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:119--> The <syntaxhighlight lang="json" inline>$schema</syntaxhighlight> attribute is a schema definition file that allows you to validate your file using JSON Schema. Read [https://json-schema.org/understanding-json-schema/index.html the official website] for more information on JSON schema validation works.</translate> | <translate><!--T:119--> The <syntaxhighlight lang="json" inline>$schema</syntaxhighlight> attribute is a schema definition file that allows you to validate your file using JSON Schema. Read [https://json-schema.org/understanding-json-schema/index.html the official website] for more information on how JSON schema validation works.</translate> | ||
<translate><!--T:120--> '''Note | <translate><!--T:120--> '''Note''' Having ''joomla.asset.json'' for your extension or template are recommended but not required for WebAsset to work. (See the next section).</translate> | ||
<translate><!--T:121--> '''Note''' It is not recommended to add an inline asset to a JSON file | <translate><!--T:121--> '''Note''' It is not recommended to add an inline asset to a JSON file. Prefer to use a file.</translate> | ||
<translate> | <translate> | ||
| Line 71: | Line 71: | ||
<translate> | <translate> | ||
<!--T:124--> | <!--T:124--> | ||
'''Registered''' is where an asset is loaded into '''WebAssetRegistry'''. That means '''WebAssetManager''' knows about the existence of these assets, but will not attach them to a document while rendering. | '''Registered''' is where an asset is loaded into '''WebAssetRegistry'''. That means '''WebAssetManager''' knows about the existence of these assets, but will not attach them to a document while rendering. All assets loaded from joomla.asset.json is at '''registered''' stage.</translate> | ||
All assets loaded from joomla.asset.json is at '''registered''' stage.</translate> | |||
<translate><!--T:125--> '''Used''' is where an asset is enabled via "$wa->useAsset()" (->useScript(), ->useStyle(), ->registerAndUseX() etc). That means '''WebAssetManager''' will attach these assets and their dependencies to a document while rendering.</translate> | <translate><!--T:125--> '''Used''' is where an asset is enabled via "$wa->useAsset()" (->useScript(), ->useStyle(), ->registerAndUseX() etc). That means '''WebAssetManager''' will attach these assets and their dependencies to a document while rendering.</translate> | ||
<translate><!--T:126--> An asset cannot be used if it was not registered before | <translate><!--T:126--> An asset cannot be used if it was not registered before. This will cause an unknown asset exception.</translate> | ||
<translate> | <translate> | ||
| Line 82: | Line 81: | ||
</translate> | </translate> | ||
<translate><!--T:128--> All known assets loaded and then stored in '''WebAssetRegistry''' ( | <translate><!--T:128--> All known assets loaded and then stored in '''WebAssetRegistry'''. (To enable/disable an asset item, use '''WebAssetManager'''. See the next section.)</translate> | ||
<translate><!--T:129--> Joomla! will look for next assets definition automatically at runtime (in following order):</translate> | <translate><!--T:129--> Joomla! will look for next assets definition automatically at runtime (in following order):</translate> | ||
| Line 93: | Line 92: | ||
</pre> | </pre> | ||
<translate><!--T:130--> And load them to registry of known assets.</translate> | <translate><!--T:130--> And load them to the registry of known assets.</translate> | ||
<translate><!--T:131--> '''Note | <translate><!--T:131--> '''Note''' Each following assets definition will override asset items from previous assets definition, by item name.</translate> | ||
<translate><!--T:132--> You can register your own assets definition via '''WebAssetRegistry''':</translate> | <translate><!--T:132--> You can register your own assets definition via '''WebAssetRegistry''':</translate> | ||
| Line 116: | Line 115: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:135--> The new asset item | <translate><!--T:135--> The new asset item ''foobar'' will be added to the registry of know assets, but will not be attached to a document until your code (a layout, template etc) will request it.</translate> | ||
<translate><!--T:136--> To check whether an asset exists:</translate> | <translate><!--T:136--> To check whether an asset exists:</translate> | ||
| Line 132: | Line 131: | ||
<translate><!--T:139--> By using AssetManager you can enable or disable needed asset easily in Joomla! through a standard methods.</translate> | <translate><!--T:139--> By using AssetManager you can enable or disable needed asset easily in Joomla! through a standard methods.</translate> | ||
<translate><!--T:140--> To enable an asset in the page use the useAsset function | <translate><!--T:140--> To enable an asset in the page, use the useAsset function:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 151: | Line 150: | ||
<translate><!--T:141--> '''WebAssetManager''' will look to '''WebAssetRegistry''' whether the requested asset exists, and will enable it for current Document instance. Otherwise it will throw an UnknownAssetException.</translate> | <translate><!--T:141--> '''WebAssetManager''' will look to '''WebAssetRegistry''' whether the requested asset exists, and will enable it for current Document instance. Otherwise it will throw an UnknownAssetException.</translate> | ||
<translate><!--T:142--> To disable an asset in the page use the disableAsset function. The example below will disable the jquery-noconflict asset from being loaded.</translate> | <translate><!--T:142--> To disable an asset in the page use the ''disableAsset'' function. The example below will disable the ''jquery-noconflict'' asset from being loaded.</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 159: | Line 158: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:143--> '''Note''' If there are any dependencies to the disabled asset, | <translate><!--T:143--> '''Note''' If there are any dependencies to the disabled asset, this asset will be re-enabled automatically, no matter what.</translate> | ||
<translate><!--T:144--> To check whether asset enabled, and the asset state:</translate> | <translate><!--T:144--> To check whether an asset is enabled, and the asset state:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
// Checking whether an asset are active (enabled manually or automatically as dependency) | // Checking whether an asset are active (enabled manually or automatically as dependency). | ||
if ($wa->isAssetActive('script', 'foobar')) | if ($wa->isAssetActive('script', 'foobar')) | ||
{ | { | ||
| Line 189: | Line 188: | ||
<translate><!--T:146--> | <translate><!--T:146--> | ||
Overriding may be useful when you need to redefine the URI of asset item or its dependencies. | Overriding may be useful when you need to redefine the URI of asset item or its dependencies. | ||
As already | As already noted, each of the following assets definition from joomla.asset.json will override asset items from previous assets definitions, by item name.</translate> | ||
<translate><!--T:147--> | <translate><!--T:147--> | ||
If you provide joomla.asset.json which contains already loaded asset items, they will be replaced with your items. | |||
Another way to override in the code is to register an item with the same name. | Another way to override in the code is to register an item with the same name. | ||
Example, we have | Example, we have ''foobar'' script, that loads the ''com_example/foobar.js'' library, and we want to use CDN for this exact library:</translate> | ||
<translate><!--T:148--> How it defined in the system initially:</translate> | <translate><!--T:148--> How it defined in the system initially:</translate> | ||
| Line 208: | Line 207: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:149--> To override the URI we define the asset item with | <translate><!--T:149--> To override the URI, we define the asset item with ''foobar'' name in our joomla.asset.json:</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 231: | Line 230: | ||
</translate> | </translate> | ||
<translate><!--T:152--> AssetManager | <translate><!--T:152--> AssetManager allows you to manage style sheet files. Style sheet asset items have a type "style".</translate> | ||
<translate><!--T:153--> Example JSON definition of item in joomla.asset.json:</translate> | <translate><!--T:153--> Example JSON definition of item in joomla.asset.json:</translate> | ||
| Line 278: | Line 277: | ||
Inline styles may be placed directly before the dependency, after the dependency, or as usual after all styles.</translate> | Inline styles may be placed directly before the dependency, after the dependency, or as usual after all styles.</translate> | ||
<translate><!--T:158--> Inline asset may have a name as well as other assets (but not required) | <translate><!--T:158--> Inline asset may have a name as well as other assets (but not required). The name can be used to retrieve the asset item from a registry, or as a dependency to another inline asset. If the name is not specified then a generated name based on a content hash will be used.</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 297: | Line 296: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:159--> '''Note | <translate><!--T:159--> '''Note''' The ''foobar'' asset should exist in the asset registry, otherwise you will get an unsatisfied dependency exception.</translate> | ||
<translate><!--T:160--> | <translate><!--T:160--> The example above will produce:</translate> | ||
<syntaxhighlight lang="html5"> | <syntaxhighlight lang="html5"> | ||
| Line 313: | Line 312: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:161--> If inline asset has multiple dependencies, then will be used last one for positioning. Example:</translate> | <translate><!--T:161--> If an inline asset has multiple dependencies, then will be used last one for positioning. Example:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 330: | Line 329: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:163--> '''Note | <translate><!--T:163--> '''Note''' Named inline assets may be a dependency to another inline asset, however it is not recommended to use an inline asset as dependency to non-inline asset. This will work, but this behavior may change in the future. Prefer to use ''position'' instead.</translate> | ||
<translate> | <translate> | ||
| Line 336: | Line 335: | ||
</translate> | </translate> | ||
<translate><!--T:165--> AssetManager allow to manage | <translate><!--T:165--> AssetManager allow you to manage JavaScript files. Script asset items have a type "script".</translate> | ||
<translate><!--T:166--> Example JSON definition of item in joomla.asset.json:</translate> | <translate><!--T:166--> Example JSON definition of item in joomla.asset.json:</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 382: | Line 381: | ||
</translate> | </translate> | ||
<translate><!--T:169--> AssetManager | <translate><!--T:169--> AssetManager offers these methods to work with script files:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 408: | Line 407: | ||
<translate><!--T:171--> | <translate><!--T:171--> | ||
In addition to script files, WebAssetManager allows you to add an inline script, and maintain their relation to the file asset. | |||
Inline script may be placed directly before the dependency, after the dependency, or as usual after all scripts.</translate> | Inline script may be placed directly before the dependency, after the dependency, or as usual after all scripts.</translate> | ||
<translate><!--T:172--> Inline asset may have a name as well as other assets (but not required) | <translate><!--T:172--> Inline asset may have a name as well as other assets (but not required). The name can be used to retrieve the asset item form a registry, or as dependency to another inline asset. If a name is not specified, a generated name based on a content hash will be used.</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 433: | Line 432: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:173--> '''Note | <translate><!--T:173--> '''Note''' The ''foobar'' asset should exist in the asset registry, otherwise you will get an unsatisfied dependency exception.</translate> | ||
<translate><!--T:174--> Example above will produce:</translate> | <translate><!--T:174--> Example above will produce:</translate> | ||
| Line 450: | Line 449: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:175--> If inline asset | <translate><!--T:175--> If an inline asset has multiple dependencies, it will be the last one for positioning. Example:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 468: | Line 467: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:177--> '''Note | <translate><!--T:177--> '''Note''' Named inline assets may be a dependency on another inline asset, however it is not recommended to use an inline asset as dependency to non-inline asset. This will work, but this behavior may changes in future. Prefer to use ''position'' instead.</translate> | ||
<translate> | <translate> | ||
| Line 475: | Line 474: | ||
<translate><!--T:179--> | <translate><!--T:179--> | ||
Joomla! allows you to use [https://developer.mozilla.org/en-US/docs/Web/Web_Components Web Components] for your needs. In Joomla! web components are not loaded as regular | Joomla! allows you to use [https://developer.mozilla.org/en-US/docs/Web/Web_Components Web Components] for your needs. In Joomla! web components are not loaded as regular scripts, but loaded via Web Component loader so that they are loaded asynchronously. Therefore, a web component asset item must have a flag ''webcomponent'' set to the boolean ''true''. | ||
In all other aspects, working with web components in AssetManager is the same as working with a | In all other aspects, working with web components in AssetManager is the same as working with a ''script'' asset item.</translate> | ||
<translate><!--T:180--> Example JSON | <translate><!--T:180--> Example JSON definitions of some web components in joomla.asset.json (as ES6 module):</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 533: | Line 532: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:182--> Alternatively you can register them in PHP (as ES6 module):</translate> | <translate><!--T:182--> Alternatively you can register them in PHP (as an ES6 module):</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 549: | Line 548: | ||
<translate> | <translate> | ||
<!--T:184--> | <!--T:184--> | ||
'''Note | '''Note''' It is preferred to prefix the asset name with ''webcomponent.'' to make it easily to spot, and distinguish it from regular scripts in a layout.</translate> | ||
<translate> | <translate> | ||
| Line 555: | Line 554: | ||
</translate> | </translate> | ||
<translate><!--T:186--> All methods to work with a web component are the same as methods to work with script asset | <translate><!--T:186--> All methods to work with a web component are the same as methods to work with script asset items.</translate> | ||
<translate> | <translate> | ||
| Line 562: | Line 561: | ||
<translate><!--T:188--> | <translate><!--T:188--> | ||
A ''preset'' is a special kind of asset item that holds a list of items to be enabled, in the same way as direct call of ''useAsset()'' to each of item in the list. | |||
Preset can hold mixed types of assets (script, style, another preset, etc) | Preset can hold mixed types of assets (script, style, another preset, etc.). The type should be provided after a # symbol and follows after an asset name. Example: foo#style, bar#script.</translate> | ||
<translate><!--T:189--> Example JSON definition of item in joomla.asset.json:</translate> | <translate><!--T:189--> Example JSON definition of item in joomla.asset.json:</translate> | ||
| Line 586: | Line 585: | ||
</translate> | </translate> | ||
<translate><!--T:191--> AssetManager | <translate><!--T:191--> AssetManager offers these methods to work with preset items:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 616: | Line 615: | ||
<translate><!--T:194--> You are also allowed to use a custom class, which must implement '''Joomla\CMS\WebAsset\WebAssetItemInterface''' or extend '''Joomla\CMS\WebAsset\WebAssetItem'''.</translate> | <translate><!--T:194--> You are also allowed to use a custom class, which must implement '''Joomla\CMS\WebAsset\WebAssetItemInterface''' or extend '''Joomla\CMS\WebAsset\WebAssetItem'''.</translate> | ||
<translate><!--T:195--> A custom class | <translate><!--T:195--> A custom class allows you to do advanced actions. For example, including a script file depending on an active language:</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 638: | Line 637: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:196--> Additionally, implementing | <translate><!--T:196--> Additionally, implementing ''Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface'' allows you to add script options (which may depend on the environment) when your asset is enabled and attached to the Document.</translate> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Line 651: | Line 650: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:197--> '''Important | <translate><!--T:197--> '''Important Note''' An asset item that implements ''WebAssetAttachBehaviorInterface'' should be enabled before a [https://docs.joomla.org/Plugin/Events/System#onBeforeCompileHead onBeforeCompileHead] event, otherwise ''onAttachCallback'' will be ignored.</translate> | ||
<translate> | <translate> | ||
| Line 658: | Line 657: | ||
<translate><!--T:199--> | <translate><!--T:199--> | ||
In joomla.asset.json you can define which Class should be used with specific AssetItem. | In joomla.asset.json you can define which Class should be used with a specific AssetItem. | ||
For this you can use | For this you can use two properties '''namespace''' and '''class'''. '''namespace''' can be defined at Root level. (Then it will be used as default namespace for all Asset items in joomla.asset.json) or in the Item level. For example:</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 685: | Line 684: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:200--> Here the asset | <translate><!--T:200--> Here the asset ''foo'' will be associated with class ''Joomla\Component\Example\WebAsset\FooAssetItem'', and ''bar'' with class ''MyFooBar\Library\Example\WebAsset\BarAssetItem''.</translate> | ||
<translate><!--T:201--> '''Note | <translate><!--T:201--> '''Note''' If ''namespace'' is not defined, by default ''Joomla\CMS\WebAsset'' will be used. When ''namespace'' is defined but empty, no namespace will be used, only ''class''. Example:</translate> | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
| Line 711: | Line 710: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<translate><!--T:202--> Here the asset | <translate><!--T:202--> Here the asset ''foo'' will be associated with class ''Joomla\CMS\WebAsset\FooAssetItem'', and ''bar'' with class ''BarAssetItem'' (without namespace).</translate> | ||
<noinclude> | <noinclude> | ||
Revision as of 23:51, 2 May 2023
Concept
In the Frontend world many assets are related. For example, our keepalive script depends on the core.js file for options management. In Joomla there never was an easy way to specify this; you just had to include multiple files. Joomla 4 changes this with the concept of web assets.
Definition
Related assets are defined in a JSON file such as system/joomla.asset.json#L14-L21
This has a structure of having a schema definition (for validation), name, version, license and then one or more asset definitions. Assets comprise a list of JavaScript files and CSS files related to the assets and any dependencies. The dependencies section is just a list of asset names that are required for the asset to function. Example:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "com_example",
"version": "4.0.0",
"description": "Joomla CMS",
"license": "GPL-2.0+",
"assets": [
{
"name": "bar",
"type": "style",
"uri": "com_example/bar.css"
},
{
"name": "bar",
"type": "script",
"uri": "com_example/bar.js"
},
{
"name": "beer",
"type": "style",
"uri": "com_example/beer.css",
"dependencies": [
"bar"
],
},
{
"name": "beer",
"type": "script",
"dependencies": [
"core",
"bar"
],
"uri": "com_example/beer.js",
"attributes": {
"defer": true,
"data-foo": "bar"
}
}
]
}
The $schema attribute is a schema definition file that allows you to validate your file using JSON Schema. Read the official website for more information on how JSON schema validation works.
Note Having joomla.asset.json for your extension or template are recommended but not required for WebAsset to work. (See the next section).
Note It is not recommended to add an inline asset to a JSON file. Prefer to use a file.
Explaining Asset Stages
Each asset has two stages: registered and used.
Registered is where an asset is loaded into WebAssetRegistry. That means WebAssetManager knows about the existence of these assets, but will not attach them to a document while rendering. All assets loaded from joomla.asset.json is at registered stage.
Used is where an asset is enabled via "$wa->useAsset()" (->useScript(), ->useStyle(), ->registerAndUseX() etc). That means WebAssetManager will attach these assets and their dependencies to a document while rendering.
An asset cannot be used if it was not registered before. This will cause an unknown asset exception.
Register an Asset
All known assets loaded and then stored in WebAssetRegistry. (To enable/disable an asset item, use WebAssetManager. See the next section.)
Joomla! will look for next assets definition automatically at runtime (in following order):
media/vendor/joomla.asset.json (on first access to WebAssetRegistry)
media/system/joomla.asset.json
media/legacy/joomla.asset.json
media/{com_active_component}/joomla.asset.json (on dispatch the application)
templates/{active_template}/joomla.asset.json
And load them to the registry of known assets.
Note Each following assets definition will override asset items from previous assets definition, by item name.
You can register your own assets definition via WebAssetRegistry:
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wr = $wa->getRegistry();
$wr->addRegistryFile('relative/path/to/your/joomla.asset.json');
To add a custom asset item at runtime:
$wr->add('script', new Joomla\CMS\WebAsset\WebAssetItem('foobar', 'com_foobar/file.js', ['type' => 'script']));
Or more simply, using WebAssetManager:
$wa->registerScript('foobar', 'com_foobar/file.js');
The new asset item foobar will be added to the registry of know assets, but will not be attached to a document until your code (a layout, template etc) will request it.
To check whether an asset exists:
if ($wa->assetExists('script', 'foobar'))
{
var_dump('Script "foobar" exists!');
}
Enabling an Asset
All asset management in the current Document handled by WebAssetManager, which is accessible with $doc->getWebAssetManager(); By using AssetManager you can enable or disable needed asset easily in Joomla! through a standard methods.
To enable an asset in the page, use the useAsset function:
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->useScript('keepalive');
// Or multiple
$wa->useScript('keepalive')
->useScript('fields.validate')
->useStyle('foobar')
->useScript('foobar');
// Add new asset item with dependency and use it
$wa->registerAndUseScript('bar', 'com_foobar/bar.js', [], [], ['core', 'foobar']);
WebAssetManager will look to WebAssetRegistry whether the requested asset exists, and will enable it for current Document instance. Otherwise it will throw an UnknownAssetException.
To disable an asset in the page use the disableAsset function. The example below will disable the jquery-noconflict asset from being loaded.
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->disableScript('jquery-noconflict');
Note If there are any dependencies to the disabled asset, this asset will be re-enabled automatically, no matter what.
To check whether an asset is enabled, and the asset state:
// Checking whether an asset are active (enabled manually or automatically as dependency).
if ($wa->isAssetActive('script', 'foobar'))
{
var_dump('Script "foobar" is active!');
}
// Checking state
switch($wa->getAssetState('script', 'foobar')){
case Joomla\CMS\WebAsset\WebAssetManager::ASSET_STATE_ACTIVE:
var_dump('Active! Was enabled manually');
break;
case Joomla\CMS\WebAsset\WebAssetManager::ASSET_STATE_DEPENDENCY:
var_dump('Active! Was enabled automatically while resolving dependencies');
break;
default:
var_dump('not active!');
}
Overriding an Asset
Overriding may be useful when you need to redefine the URI of asset item or its dependencies. As already noted, each of the following assets definition from joomla.asset.json will override asset items from previous assets definitions, by item name. If you provide joomla.asset.json which contains already loaded asset items, they will be replaced with your items. Another way to override in the code is to register an item with the same name. Example, we have foobar script, that loads the com_example/foobar.js library, and we want to use CDN for this exact library:
How it defined in the system initially:
...
{
"name": "foobar",
"type": "script",
"uri": "com_example/foobar.js",
"dependencies": ["core"]
}
...
To override the URI, we define the asset item with foobar name in our joomla.asset.json:
...
{
"name": "foobar",
"type": "script",
"uri": "http://foobar.cdn.blabla/foobar.js",
"dependencies": ["core"]
}
...
Or, register new asset item with AssetManager:
$wa->registerScript('foobar', 'http://fobar.cdn.blabla/foobar.js', [], [], ['core']);
Working with Styles
AssetManager allows you to manage style sheet files. Style sheet asset items have a type "style".
Example JSON definition of item in joomla.asset.json:
...
{
"name": "foobar",
"type": "style",
"uri": "com_example/foobar.css"
}
...
Methods to Work with Styles
AssetManager offers the following methods to work with style files:
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Attach foobar to the document
$wa->useStyle('foobar');
// Disable foobar from being attached
$wa->disableStyle('foobar');
// Register custom item without JSON definition
$wa->registerStyle('bar', 'com_example/bar.css', [], ['data-foo' => 'some attribute'], ['some.dependency']);
// And use it later
$wa->useStyle('bar');
// Register and attach a custom item in one run
$wa->registerAndUseStyle('bar', 'com_example/bar.css', [], ['data-foo' => 'some attribute'], ['some.dependency']);
Add Inline Style
Additionally to style files, WebAssetManager allows you to add an inline style, and maintain their relation to the file asset. Inline styles may be placed directly before the dependency, after the dependency, or as usual after all styles.
Inline asset may have a name as well as other assets (but not required). The name can be used to retrieve the asset item from a registry, or as a dependency to another inline asset. If the name is not specified then a generated name based on a content hash will be used.
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Add an inline content as usual, will be rendered in flow after all assets
$wa->addInlineStyle('content of inline1');
// Add an inline content that will be placed after "foobar" asset
$wa->addInlineStyle('content of inline2', ['position' => 'after'], ['data-foo' => 'bar'], ['foobar']);
// Add an inline content that will be placed before "foobar" asset
$wa->addInlineStyle('content of inline3', ['position' => 'before'], [], ['foobar']);
// Named inline asset
$wa->addInlineStyle('content of inline4', ['name' => 'my.inline.asset']);
Note The foobar asset should exist in the asset registry, otherwise you will get an unsatisfied dependency exception.
The example above will produce:
...
<style>content of inline3</style>
<link rel="stylesheet" href="foobar.css" />
<style data-foo="bar">content of inline2</style>
...
...
<style>content of inline1</style>
<style>content of inline4</style>
...
If an inline asset has multiple dependencies, then will be used last one for positioning. Example:
$wa->addInlineStyle('content of inline1', ['position' => 'before'], [], ['foo', 'bar']);
$wa->addInlineStyle('content of inline2', ['position' => 'after'], [], ['foo', 'bar']);
Will produce:
...
<link rel="stylesheet" href="foo.css" />
<style>content of inline1</style>
<link rel="stylesheet" href="bar.css" />
<style>content of inline2</style>
...
Note Named inline assets may be a dependency to another inline asset, however it is not recommended to use an inline asset as dependency to non-inline asset. This will work, but this behavior may change in the future. Prefer to use position instead.
Working with Scripts
AssetManager allow you to manage JavaScript files. Script asset items have a type "script". Example JSON definition of item in joomla.asset.json:
...
{
"name": "foobar",
"type": "script",
"uri": "com_example/foobar.js",
"dependencies": ["core"]
}
...
Example JSON definition of ES6 module script, with fallback to legacy:
...
{
"name": "foobar-legacy",
"type": "script",
"uri": "com_example/foobar-as5.js",
"attributes": {
"nomodule": true,
"defer": true
},
"dependencies": ["core"]
}
{
"name": "foobar",
"type": "script",
"uri": "com_example/foobar.js",
"attributes": {
"type": "module"
},
"dependencies": [
"core",
"foobar-legacy"
]
}
...
Methods to Work with Scripts
AssetManager offers these methods to work with script files:
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Attach foobar to the document
$wa->useScript('foobar');
// Disable foobar from being attached
$wa->disableScript('foobar');
// Register custom item without JSON definition
$wa->registerScript('bar', 'com_example/bar.js', [], ['defer' => true], ['core']);
// And use it later
$wa->useScript('bar');
// Register and attach a custom item in one run
$wa->registerAndUseScript('bar','com_example/bar.js', [], ['defer' => true], ['core']);
Add Inline Script
In addition to script files, WebAssetManager allows you to add an inline script, and maintain their relation to the file asset. Inline script may be placed directly before the dependency, after the dependency, or as usual after all scripts.
Inline asset may have a name as well as other assets (but not required). The name can be used to retrieve the asset item form a registry, or as dependency to another inline asset. If a name is not specified, a generated name based on a content hash will be used.
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Add an inline content as usual, will be rendered in flow after all assets
$wa->addInlineScript('content of inline1');
// Add an inline content that will be placed after "foobar" asset
$wa->addInlineScript('content of inline2', ['position' => 'after'], ['data-foo' => 'bar'], ['foobar']);
// Add an inline content that will be placed before "foobar" asset
$wa->addInlineScript('content of inline3', ['position' => 'before'], [], ['foobar']);
// Named inline asset
$wa->addInlineScript('content of inline4', ['name' => 'my.inline.asset']);
// Specify script type
$wa->addInlineScript('content of inline5', [], ['type' => 'module']);
Note The foobar asset should exist in the asset registry, otherwise you will get an unsatisfied dependency exception.
Example above will produce:
...
<script>content of inline3</script>
<script src="foobar.js"></script>
<script data-foo="bar">content of inline2</script>
...
...
<script>content of inline1</script>
<script>content of inline4</script>
<script type="module">content of inline5</script>
...
If an inline asset has multiple dependencies, it will be the last one for positioning. Example:
$wa->addInlineScript('content of inline1', ['position' => 'before'], [], ['foo', 'bar']);
$wa->addInlineScript('content of inline2', ['position' => 'after'], [], ['foo', 'bar']);
Will produce:
...
<script src="foo.js"></script>
<script>content of inline1</script>
<script src="bar.js"></script>
<script>content of inline2</script>
...
Note Named inline assets may be a dependency on another inline asset, however it is not recommended to use an inline asset as dependency to non-inline asset. This will work, but this behavior may changes in future. Prefer to use position instead.
Working with a Web Component
Joomla! allows you to use Web Components for your needs. In Joomla! web components are not loaded as regular scripts, but loaded via Web Component loader so that they are loaded asynchronously. Therefore, a web component asset item must have a flag webcomponent set to the boolean true. In all other aspects, working with web components in AssetManager is the same as working with a script asset item.
Example JSON definitions of some web components in joomla.asset.json (as ES6 module):
...
{
"name": "webcomponent.foobar",
"type": "style",
"uri": "com_example/foobar-custom-element.css",
},
{
"name": "webcomponent.foobar",
"type": "script",
"uri": "com_example/foobar-custom-element.js",
"attributes": {
"type": "module"
},
}
...
Example with fallback, for browsers that does not support ES6 "module" feature. Note that the legacy script should have "wcpolyfill" dependency, and module script should have dependency from legacy script:
...
{
"name": "webcomponent.foobar",
"type": "style",
"uri": "com_example/foobar-custom-element.css",
},
{
"name": "webcomponent.foobar-legacy",
"type": "script",
"uri": "com_example/foobar-custom-element-es5.js",
"attributes": {
"nomodule": true,
"defer": true
},
"dependencies": [
"wcpolyfill"
]
},
{
"name": "webcomponent.foobar",
"type": "script",
"uri": "com_example/foobar-custom-element.js",
"attributes": {
"type": "module"
},
"dependencies": [
"webcomponent.foobar-legacy"
]
}
...
Alternatively you can register them in PHP (as an ES6 module):
$wa->registerStyle('webcomponent.foobar', 'com_example/foobar-custom-element.css')
->registerScript('webcomponent.foobar', 'com_example/foobar-custom-element.js', ['type' => 'module']);
Attach to document:
$wa->useStyle('webcomponent.foobar')
->useScript('webcomponent.foobar');
Note It is preferred to prefix the asset name with webcomponent. to make it easily to spot, and distinguish it from regular scripts in a layout.
Methods to Work with Web Component
All methods to work with a web component are the same as methods to work with script asset items.
Working with a Presets
A preset is a special kind of asset item that holds a list of items to be enabled, in the same way as direct call of useAsset() to each of item in the list. Preset can hold mixed types of assets (script, style, another preset, etc.). The type should be provided after a # symbol and follows after an asset name. Example: foo#style, bar#script.
Example JSON definition of item in joomla.asset.json:
...
{
"name": "foobar",
"type": "preset",
"uri": "",
"dependencies": [
"core#script",
"foobar#style",
"foobar#script",
]
}
...
Methods to Work with Preset
AssetManager offers these methods to work with preset items:
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Attach all items from foobar preset to the document
$wa->usePreset('foobar');
// Disable all items from foobar preset from being attached
$wa->disablePreset('foobar');
// Register custom item without JSON definition
$wa->registerPreset('bar', '', [], [], ['core#script', 'bar#script']);
// And use it later
$wa->usePreset('bar');
// Register and attach a custom item in one run
$wa->registerAndUsePreset('bar','', [], [], ['core#script', 'bar#script']);
Advanced: Custom WebAssetItem Class
The default class for all WebAsset items is Joomla\CMS\WebAsset\WebAssetItem.
You are also allowed to use a custom class, which must implement Joomla\CMS\WebAsset\WebAssetItemInterface or extend Joomla\CMS\WebAsset\WebAssetItem.
A custom class allows you to do advanced actions. For example, including a script file depending on an active language:
class MyComExampleAssetItem extends WebAssetItem
{
public function getUri($resolvePath = true): string
{
$langTag = Factory::getApplication()->getLanguage()->getTag();
// For script asset use ".js", for style we would use ".css"
$path = 'com_example/bar-' . $langTag . '.js';
if ($resolvePath)
{
// For script asset use "script", for style we would use "stylesheet"
$path = $this->resolvePath($path, 'script');
}
return $path;
}
}
Additionally, implementing Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface allows you to add script options (which may depend on the environment) when your asset is enabled and attached to the Document.
class MyFancyFoobarAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface
{
public function onAttachCallback(Document $doc): void
{
$user = Factory::getApplication()->getIdentity();
$doc->addScriptOptions('com_example.fancyfoobar', ['userName' => $user->username]);
}
}
Important Note An asset item that implements WebAssetAttachBehaviorInterface should be enabled before a onBeforeCompileHead event, otherwise onAttachCallback will be ignored.
Defining a Custom WebAssetItem Class in joomla.asset.json
In joomla.asset.json you can define which Class should be used with a specific AssetItem. For this you can use two properties namespace and class. namespace can be defined at Root level. (Then it will be used as default namespace for all Asset items in joomla.asset.json) or in the Item level. For example:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "com_example",
"version": "4.0.0",
"namespace": "Joomla\Component\Example\WebAsset",
"assets": [
{
"name": "foo",
"type": "script",
"class": "FooAssetItem",
"uri": "com_example/foo.js"
},
{
"name": "bar",
"type": "script",
"namespace": "MyFooBar\Library\Example\WebAsset",
"class": "BarAssetItem",
"uri": "com_example/bar.js"
}
]
}
Here the asset foo will be associated with class Joomla\Component\Example\WebAsset\FooAssetItem, and bar with class MyFooBar\Library\Example\WebAsset\BarAssetItem.
Note If namespace is not defined, by default Joomla\CMS\WebAsset will be used. When namespace is defined but empty, no namespace will be used, only class. Example:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "com_example",
"assets": [
{
"name": "foo",
"type": "script",
"class": "FooAssetItem",
"uri": "com_example/foo.js"
},
{
"name": "bar",
"type": "script",
"namespace": "",
"class": "BarAssetItem",
"uri": "com_example/bar.js"
}
]
}
Here the asset foo will be associated with class Joomla\CMS\WebAsset\FooAssetItem, and bar with class BarAssetItem (without namespace).