web-dev-qa-db-fra.com

Comment deux bibliothèques peuvent-elles éviter de charger deux fois la même bibliothèque Javascript?

Supposons que mon extension utilise un plugin populaire JQuery. Je peux inclure le fichier Javascript dans mon extension et y créer un lien à l'aide de JHtml::script ou une autre méthode.

Le problème est que, pour autant que je sache, une autre extension peut charger exactement la même bibliothèque Javascript, juste à une autre URL. Celles-ci auront besoin de deux requêtes HTTP au lieu d'une demande inutile.

2
Flimm

Dans Joomla, vous pouvez ajouter des scripts en utilisant JHtml::script ou $doc->addScript, et si vous ajoutez le même chemin deux fois, il ne sera inclus qu'une fois dans la sortie <head>:

JHtml::script("path/to/jquery.scrollTo.min.js");

Cela ne dédupliquera pas le même script sur des chemins différents. Malheureusement, il n'y a pas de moyen intégré de le faire que je puisse voir. Pour JQuery lui-même, vous pouvez utiliser la bibliothèque fournie PHP:

JHTML::_('jquery.framework');

Hacky way côté serveur:

Vous pouvez utiliser cette façon hacky. Il vérifie simplement tous les scripts déjà ajoutés et ajoute le nouveau chemin si aucun des scripts existants ne correspond à une expression régulière:

if (! isScriptAdded('/^jquery\.scrollTo\b.*\.js$/')) {
    JHtml::script("path/tojquery.scrollTo.min.js");                                                                                   
}

function isScriptAdded($scriptRegex) {
    $document = JFactory::getDocument();
    $headData = $document->getHeadData(); # JHtml::script and $document->addScript add to this
    foreach ($headData['scripts'] as $script) {
        if (preg_match($scriptRegex, basename($script))) {
            return true;
        }   
    }   
    return false;
}

Hacky way côté client:

Vous pouvez charger la bibliothèque en Javascript, en définissant une variable globale avant de le faire. Par exemple, il s’agit de l’extrait de code Javascript SDK v2.3 de Facebook:

window.fbAsyncInit = function() {
  FB.init({
    appId      : 'your-app-id',
    xfbml      : true,
    version    : 'v2.3'
  });
};

(function(d, s, id){
   var js, fjs = d.getElementsByTagName(s)[0];
   if (d.getElementById(id)) {return;}
   js = d.createElement(s); js.id = id;
   js.src = "//connect.facebook.net/en_US/sdk.js";
   fjs.parentNode.insertBefore(js, fjs);
 }(document, 'script', 'facebook-jssdk'));

La première partie définit une variable globale, window.fbAsyncInit, et la deuxième partie charge en fait le script externe en ajoutant dynamiquement un nouveau <script> tag. Si vous voulez le rendre idempotent, vous pouvez l’entourer de cette instruction if:

if (! window.fbAsyncInit) {
    // Facebook snippet here
    // ...
}

C'est hacky, parce que vous espérez que tous les autres chargent cette bibliothèque de la même manière et définissent la variable globale correctement (c'est-à-dire avant de charger et d'exécuter la bibliothèque). Dans ce cas, vous espérez surtout que les paramètres appId et version ne changent pas. En outre, il serait théoriquement préférable que le serveur envoie un seul extrait, au lieu de plusieurs extraits qui se détectent mutuellement.

Qu'en est-il d'utiliser un CDN?

Certaines bibliothèques Javascript populaires se trouvent sur des CDN bien connus. Par exemple, Google propose un CDN pour héberger Web Font Loader et d’autres bibliothèques. L'espoir est que l'agent utilisateur aura la bibliothèque dans son cache avant même qu'il ne visite votre site Web pour la première fois. Si deux extensions utilisent le même CDN, la bibliothèque n'a pas besoin d'être téléchargée deux fois. Le principal inconvénient de l'utilisation d'un CDN est que votre site Web dépend maintenant d'une tierce partie. C'est pourquoi je vous recommande de ne pas adopter cette approche par défaut avec des extensions qui seront partagées en ligne.

6
Flimm