J4.x

Ressources web (Web Assets)

From Joomla! Documentation

This page is a translated version of the page J4.x:Web Assets and the translation is 20% complete.
Outdated translations are marked like this.
Other languages:
Deutsch • ‎English • ‎Nederlands • ‎français • ‎italiano • ‎русский

Concept

Dans le monde du frontend, de nombreuses ressources sont liées. Par exemple, notre script keepalive dépend du fichier core.js pour la gestion des options. Dans Joomla, il n'y a jamais eu de moyen simple de spécifier cela, il suffisait d'inclure plusieurs fichiers. Joomla 4 a changé cela avec le concept des ressources web (Web Assets).

Définition

Les ressources web liées sont définies dans un fichier JSON tel que system/joomla.asset.json#L14-L21.

Sa structure est la suivante : définition du schéma (pour la validation), nom, version, licence, puis une ou plusieurs définitions de ressources. Les ressources sont composées d'une liste de fichiers js et de fichiers css liés aux ressources et à toute dépendance. La section des dépendances est juste une liste de noms de ressources qui sont nécessaires pour que la ressource fonctionne. Exemple :

{
  "$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"
      }
    }
  ]
}

L'attribut $schema est un fichier de définition de schéma qui vous permet de valider votre fichier en utilisant le schéma JSON. Consultez le site officiel pour plus d'informations sur le fonctionnement de la validation du schéma JSON.

Note: Avoir joomla.asset.json pour votre extension ou template est recommandé mais pas obligatoire pour que WebAssset fonctionne (voir section suivante).

Note: Il n'est pas recommandé d'ajouter un actif en ligne à un fichier json, préférez utiliser un fichier.

Explication des phases de ressources

Chaque ressource a 2 phases : enregistrée et utilisée.

Registered est le moment où une ressource est téléchargée dans WebAssetRegistry. Cela signifie que le WebAssetManager connaît l'existence de ces ressources, mais ne les attachera pas à un document lors du rendu. Toutes les ressources téléchargées à partir de joomla.asset.json sont à l'étape registered.

Used est le cas où une ressource est activée via "$wa->useAsset()" (->useScript(), ->useStyle(), ->registerAndUseX() etc). Cela signifie que WebAssetManager attachera ces ressources et leurs dépendances à un document lors du rendu.

Une ressource ne peut pas être utilisée si elle n'a pas été enregistrée auparavant, ce qui entraînera une exception de ressource inconnue.

Enregistrer une ressource

Tous les ressources connues sont chargées et stockées dans WebAssetRegistry (pour activer/désactiver une ressource, vous devez utiliser WebAssetManager, voir la section suivante).

Joomla ! recherchera automatiquement la définition des ressources suivantes au moment de l'exécution (dans l'ordre suivant) :

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

Et les téléchargera dans le registre des ressources connues.

Note : Chaque définition de ressources suivante remplacera les éléments de ressources de la définition de la précédente, par nom d'élément.

Vous pouvez enregistrer vos propres définitions de ressources 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');

Pour ajouter un élément de ressource personnalisé au moment de l'exécution :

$wr->add('script', new Joomla\CMS\WebAsset\WebAssetItem('foobar', 'com_foobar/file.js', ['type' => 'script']));

Ou plus simplement, en utilisant WebAssetManager :

$wa->registerScript('foobar', 'com_foobar/file.js');

Le nouvel élément de ressource foobar sera ajouté au registre des ressources connues, mais ne sera pas attaché à un document avant que votre code (une mise en page, un template, etc.) ne le demande.

Pour vérifier si une ressource existe :

if ($wa->assetExists('script', 'foobar'))
{
    var_dump('Script "foobar" exists!');
}

Activation d'une ressource

Toute la gestion des ressources dans le document actuel est gérée par WebAssetManager, qui est accessible avec $doc->getWebAssetManager();". En utilisant AssetManager, vous pouvez activer ou désactiver facilement la ressource nécessaire dans Joomla ! par le biais d'une méthode standard.

Pour activer une ressource dans la page, utilisez la fonction useAsset, par exemple :

/** @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 the new asset item with dependency and use it
$wa->registerAndUseScript('bar', 'com_foobar/bar.js', [], [], ['core', 'foobar']);

Le WebAssetManager vérifiera dans le WebAssetRegistry si la ressource demandée existe et l'activera pour l'instance de document actuelle. Dans le cas contraire, il lèvera une exception de type UnknownAssetException.

Pour désactiver une ressource dans la page, utilisez la fonction disableAsset. L'exemple ci-dessous empêchera le chargement de la ressource jquery-noconflict.

/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->disableScript('jquery-noconflict');

Note: S'il existe des dépendances à la ressource désactivée, cette dernière sera réactivée automatiquement, quoi qu'il arrive.

Pour vérifier si la ressource est activée et l'état de la ressource :

// 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!');
}

Remplacement de la ressource

La surcharge peut être utile lorsque vous devez redéfinir l'URI d'un élément de ressource ou de ses dépendances. Comme nous l'avons déjà noté, chacune des définitions de ressources suivantes de joomla.asset.json remplacera les éléments de ressources des définitions de ressources précédentes, par nom d'élément.

Cela signifie que si vous fournissez un fichier joomla.asset.json contenant des ressources déjà chargées, celles-ci seront remplacées par les vôtres. Une autre façon de remplacer dans le code est d'enregistrer un élément avec le même nom. Par exemple, nous avons un script "foobar" qui charge la bibliothèque com_example/foobar.js, et nous voulons utiliser le CDN pour cette bibliothèque exacte :

Comment il a été défini initialement dans le système :

...
{
  "name": "foobar",
  "type": "script",
  "uri": "com_example/foobar.js",
  "dependencies": ["core"]
}
...

Pour remplacer l'URI, nous définissons l'élément de ressource avec le nom "foobar" dans notre fichier joomla.asset.json :

...
{
  "name": "foobar",
  "type": "script",
  "uri": "http://foobar.cdn.blabla/foobar.js",
  "dependencies": ["core"]
}
...

Ou enregistrer un nouvel élément de ressource auprès de l'AssetManager :

$wa->registerScript('foobar', 'http://fobar.cdn.blabla/foobar.js', [], [], ['core']);

Travailler avec les styles

AssetManager permet de gérer les fichiers de feuilles de style. Les éléments des feuilles de style sont de type "style".

Exemple de définition json d'un élément dans joomla.asset.json :

...
{
  "name": "foobar",
  "type": "style",
  "uri": "com_example/foobar.css"
}
...

Méthodes pour travailler avec les styles

AssetManager propose les méthodes suivantes pour travailler avec les fichiers de style :

/** @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']);

Ajouter un style en ligne

En plus des fichiers de style, WebAssetManager vous permet d'ajouter un style en ligne, et de maintenir leur relation avec le fichier ressource. Les styles en ligne peuvent être placés directement avant la dépendance, après la dépendance ou, comme d'habitude, après tous les styles.

Le nom peut être utilisé pour récupérer la ressource dans un registre ou comme dépendance d'une autre ressource en ligne. Si le nom n'est pas spécifié, un nom généré à partir d'un hachage de contenu sera utilisé.

/** @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: La ressource "foobar" doit exister dans le registre des ressources, sinon vous obtiendrez une exception de dépendance non satisfaite.

L'exemple ci-dessus produira :

...
<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>
...

Si la ressource en ligne a plusieurs dépendances, c'est la dernière qui sera utilisée pour le positionnement. Exemple :

$wa->addInlineStyle('content of inline1', ['position' => 'before'], [], ['foo', 'bar']);
$wa->addInlineStyle('content of inline2', ['position' => 'after'], [], ['foo', 'bar']);

Produira :

...
<link rel="stylesheet" href="foo.css" />
<style>content of inline1</style>
<link rel="stylesheet" href="bar.css" />
<style>content of inline2</style>
...

Note: Les ressources en ligne nommées peuvent être dépendantes d'une autre ressource en ligne, mais il n'est pas recommandé d'en utiliser une en ligne comme dépendance d'une ressource non en ligne. Cela fonctionne, mais ce comportement pourrait changer à l'avenir. Il est préférable d'utiliser "position" à la place.

Travailler avec des scripts

AssetManager permet de gérer les fichiers Script. Les éléments script sont de type "script". Exemple de définition json d'un élément dans joomla.asset.json :

...
{
  "name": "foobar",
  "type": "script",
  "uri": "com_example/foobar.js",
  "dependencies": ["core"]
}
...

Exemple de définition json d'un script de module ES6, avec retour à l'ancienne version :

...
{
  "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"
  ]
}
...

Méthodes pour travailler avec des scripts

The 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']);

Ajouter un script en ligne

WebAssetManager permet d'ajouter des scripts en ligne aux fichiers de scripts, tout en conservant leur relation avec le fichier de la ressource. Le script en ligne peut être placé directement avant la dépendance, après la dépendance ou, comme d'habitude, après tous les scripts.

Le nom peut être utilisé pour récupérer l'élément de la ressource dans un registre ou comme dépendance d'une autre ressource en ligne. Si le nom n'est pas spécifié, il sera généré à partir d'un hachage du contenu.

/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();

// Add an inline content as usual. It 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: La ressource "foobar" doit exister dans le registre des ressources, sinon vous obtiendrez une exception de dépendance non satisfaite.

L'exemple ci-dessus produira :

...
<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>
...

Si la ressource en ligne a plusieurs dépendances, c'est la dernière qui sera utilisée pour le positionnement. Exemple :

$wa->addInlineScript('content of inline1', ['position' => 'before'], [], ['foo', 'bar']);
$wa->addInlineScript('content of inline2', ['position' => 'after'], [], ['foo', 'bar']);

Produira :

...
<script src="foo.js"></script>
<script>content of inline1</script>
<script src="bar.js"></script>
<script>content of inline2</script>
...

Note: Une ressource en ligne nommée peut être dépendante d'une autre ressource en ligne, mais il n'est pas recommandé d'utiliser une ressource en ligne comme dépendante d'une ressource non en ligne. Cela fonctionne, mais ce comportement pourrait changer à l'avenir. Il est préférable d'utiliser "position" à la place.

Utilisation d'un web component

Joomla ! vous permet d'utiliser Web Components pour vos besoins. Dans Joomla !, les Web Component ne sont pas chargés comme des scripts ordinaires, mais via le chargeur de Web Component, de sorte qu'ils sont chargés de manière asynchrone. Par conséquent, un élément de Web Component doit avoir un indicateur "webcomponent" défini sur le booléen "true". Pour le reste, l'utilisation des Web Components dans AssetManager est identique à celle d'un élément "script".

Exemple de définition json de certains web components dans joomla.asset.json (en tant que module ES6) :

...
{
  "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"
  },
}
...

Exemple avec fallback, pour les navigateurs qui ne supportent pas la fonction "module" de ES6. Notez que le script hérité doit avoir la dépendance "wcpolyfill", et que le script du module doit avoir la dépendance du script hérité :

...
{
  "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"
  ]
}
...

Vous pouvez également les enregistrer en PHP (en tant que module ES6) :

$wa->registerStyle('webcomponent.foobar', 'com_example/foobar-custom-element.css')
    ->registerScript('webcomponent.foobar', 'com_example/foobar-custom-element.js', ['type' => 'module']);

Joindre au document :

$wa->useStyle('webcomponent.foobar')
    ->useScript('webcomponent.foobar');

Note: Il est préférable de préfixer le nom de la ressource par "webcomponent." pour la rendre plus facilement repérable et la distinguer des scripts ordinaires dans une mise en page.

Méthodes pour travailler avec un web component

Toutes les méthodes permettant de travailler avec un web component sont les mêmes que celles permettant de travailler avec un élément d'actif de script.

Travailler avec un preset

Le "Preset" est un type spécial d'élément de ressource qui contient une liste d'éléments qui doivent être activés, de la même manière que l'appel direct de useAsset() à chacun des éléments de la liste. Le preset peut contenir différents types de ressources (script, style, autre preset, etc.), le type doit être indiqué après le symbole # et suivre le nom de la ressource, par exemple : foo#style, bar#script.

Exemple de définition json d'un élément dans joomla.asset.json :

...
{
  "name": "foobar",
  "type": "preset",
  "uri": "",
  "dependencies": [
    "core#script",
    "foobar#style",
    "foobar#script",
  ]
}
...

Méthodes de travail avec les presets

AssetManager propose plusieurs méthodes pour travailler avec des éléments preset :

/** @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']);

Avancé : Classe WebAssetItem personnalisée

La classe par défaut de tous les éléments de WebAsset est Joomla\CMS\WebAsset\WebAssetItem'.

Vous pouvez également utiliser une classe personnalisée, qui doit implémenter Joomla\CMS\WebAsset\WebAssetItemInterface ou étendre Joomla\CMS\WebAsset\WebAssetItem.

Une classe personnalisée peut vous permettre d'effectuer des actions avancées, par exemple l'inclusion d'un fichier script en fonction d'une langue active :

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;
	}
}

De plus, l'implémentation de Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface vous permet d'ajouter un script d'options (qui peut dépendre de l'environnement) lorsque votre ressource est activée et attachée au 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]);
	}
}

Note importante: Un élément de ressource qui implémente WebAssetAttachBehaviorInterface doit être activé avant l'événement onBeforeCompileHead, sinon l'événement 'onAttachCallback sera ignoré.

Définir une classe WebAssetItem personnalisée dans joomla.asset.json

Dans le fichier joomla.asset.json, vous pouvez définir quelle classe doit être utilisée avec un élément spécifique. Pour cela, vous pouvez utiliser 2 propriétés namespace et class. namespace peut être défini au niveau de la racine (il sera alors utilisé comme espace de noms par défaut pour tous les éléments de ressources dans joomla.asset.json) ou au niveau de l'élément. Par exemple :

{
  "$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"
    }
  ]
}

Ici, la ressource foo sera associée à la classe Joomla\Component\Example\WebAsset\FooAssetItem, et bar à la classe MyFooBar\Library\Example\WebAsset\BarAssetItem.

Note: Si namespace n'est pas défini alors par défaut sera utilisé Joomla\CMS\WebAsset. Si namespace est défini mais vide, alors aucun namespace ne sera utilisé, seulement class. Exemple :

{
  "$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"
    }
  ]
}

Ici, la ressource foo sera associée à la classe Joomla\CMS\WebAsset\FooAssetItem, et bar à la classe BarAssetItem (sans espace de noms).