Afin d'éviter de mauvaises performances avec plusieurs balises <script>
, je concatène régulièrement des scripts et ne génère qu'un seul fichier JS bundle.min.js
et un identificateur 'jsbundle'
.
Le problème est que les choses ajoutées par la suite, comme les plugins, peuvent dépendre d'une ou plusieurs bibliothèques enregistrées qui sont présentes , mais emballées dans un 'jsbundle'
générique.
Existe-t-il un moyen d'informer Wordpress que 'jsbundle'
implique, par exemple, 'jquery'
, 'backbone'
, ... afin que 1) la ressource ne soit pas chargée deux fois 2) que les choses n'échouent pas à cause d'une dépendance non remplie?
J'ai essayé avec la source de wp_register_script
, trouvé la classe WP_Scripts()
et essayé de "mentir" WP à propos des scripts disponibles, mais pas de chance.
Pour que les bibliothèques JavaScript ne soient pas chargées car vous en avez déjà créé un ensemble, procédez comme suit:
En mettant comme suit, la mise en file d'attente habituelle suivante:
function the_js() {
wp_enqueue_script('bundle_js', get_template_directory_uri() . '/js/bundle.js', array(), false, false);
}
add_action('wp_enqueue_scripts', 'the_js');
et disons que vous avez dans votre bundle les librairies suivantes (listant les handles):
jquery
backbone
colorpicker
bootstrap_js
1, 2, 3 sont déjà dans le noyau, 4 est un tiers, vous avez groupé les 4 parce que vous ne voulez pas que les 4 soient chargés en tant que ressources séparées.
Vous devez vous désinscrire (si elles sont enregistrées, les ressources de base le seraient déjà) et enregistrer chacune d'elles, chacune des bibliothèques contenues dans votre bundle:
function the_js() {
wp_enqueue_script('bundle_js', get_template_directory_uri() . '/js/bundle.js', array(), false, false);
//DEREGISTER the SCRIPTS THAT ARE IN YOUR BUNDLE
wp_deregister_script('jquery'); //because its a Core-Registered Script
wp_deregister_script('backbone'); //because its a Core-Registered Script
wp_deregister_script('colorpicker'); //because its a Core-Registered Script
//REGISTER THEM THIS TIME USING YOUR BUNDLE AS DEPENDENCY
wp_register_script('jquery', FALSE, array('bundle_js'), '', FALSE);//THE KEY HERE IS THE SRC BEING FALSE
wp_register_script('backbone', FALSE, array('bundle_js'), '', FALSE);
wp_register_script('colorpicker', FALSE, array('bundle_js'), '', FALSE);
}
add_action('wp_enqueue_scripts', 'the_js');
la clé ici est de définir le $src
comme FALSE
pour que le script enregistré soit un alias, vérifiez cette ligne dans le code principal:
// A single item may alias a set of items, by having dependencies, but no source.
if ( ! $obj->src ) {
return true;
}
c'est ce que jquery
fait actuellement, en mettant jquery
comme dépendance, il ne charge pas jquery
il charge jquery-core
et jquery-migrate
, il s'agit de l'objet enregistré pour jquery
:
object(_WP_Dependency)#329 (6) {
["handle"]=>
string(6) "jquery"
["src"]=>
bool(false)
["deps"]=>
array(2) {
[0]=>
string(11) "jquery-core"
[1]=>
string(14) "jquery-migrate"
}
["ver"]=>
string(6) "1.12.4"
["args"]=>
NULL
["extra"]=>
array(0) {
}
}
donc, bundle_js
sa sera chargée quand un script aura comme dépendance de l’une des bibliothèques (jquery
, backbone
, colorpicker
) et il sera chargé une fois, puisque la logique dans WP_Dependencies
vérifie si elle est déjà dans le tableau queue
.
Si vous voulez vérifier si un script est déjà enregistré, utilisez:
global $wp_scripts;
$wp_scripts->query('jquery'); //jquery as example handle
il retournera un objet WP_dependency
s'il est enregistré, false
s'il ne l'est pas.
Quelques liens pour mieux comprendre:
class.wp-dependencies.php
class.wp-scripts.php
functions.wp-scripts.php
La solution proposée par Alexander semble raisonnable. Vous pouvez conserver toutes les dépendances minifiées (libs.js dans mon exemple) dans un fichier et vos scripts dans un second fichier comme suit:
wp_enqueue_script( 'libs', get_template_directory_uri() . '/assets/js/libs.js', [], '1.0.0', true );
// third parameter here will make sure that libs.js is loaded before jsbundle:
wp_enqueue_script( 'jsbundle', get_template_directory_uri() . '/assets/js/jsbundle.min.js', [ 'libs' ], '1.0.0', true );
Même si regrouper des scripts est une pratique bien connue pour optimiser la vitesse de chargement des pages et une bonne idée la plupart du temps, il se peut que ce ne soit pas toujours la solution la plus performante. Je considérerais toujours d'autres options et déciderais ce qui fonctionne le mieux pour un cas d'utilisation particulier.
Vous voudrez peut-être utiliser l'un des CDN disponibles pour vos bibliothèques tierces pour obtenir tous les avantages énumérés dans cette réponse .
Par exemple. Si vous utilisez le CDN de Google ou de Facebook, il est fort probable que vos visiteurs aient déjà des scripts populaires en mémoire cache dans leur navigateur et qu'ils n'auraient pas besoin de les télécharger à nouveau.
Dans ce cas, le regroupement de scripts tiers supprime cet avantage et le regroupement complet doit être téléchargé, même si une partie de celui-ci est déjà enregistrée dans la mémoire cache du navigateur.
Vous pouvez facilement mettre en file d'attente des scripts à partir de CDN avec wp_enqueue_script()
; il vous suffit d'omettre le paramètre $ver
, car vous ne souhaitez pas actualiser le script mis en cache:
wp_enqueue_script( 'jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js', [], null, true );
L'autre chose que je considérerais est d'enregistrer plus de scripts et de ne les appeler que sur les pages où ils sont réellement utilisés. Cela fonctionne bien surtout si vous mettez souvent à jour vos scripts.
Si vous conservez tous les scripts dans un lot, l’application de quelques modifications nécessite l’analyse de cache pour l’ensemble du script. Parfois, il peut être préférable de séparer certaines parties de vos scripts afin de pouvoir changer de version uniquement pour le bloc que vous avez réellement modifié.
Supposons que j'utilise le script foo.js
sur ma page d'accueil et qu'il ne se passe pas grand-chose, donc je ne prévois pas de le changer de si tôt, mais j'ai en même temps un script compliqué bar.js
que je dois entretenir et actualiser souvent. Dans ce cas, il serait peut-être préférable d’enregistrer les scripts séparément.
En outre, certaines de vos bibliothèques peuvent n'être utilisées que sur des sous-pages qui ne sont pas visitées très souvent (disons que j'utilise masonry
sur une sous-page moins populaire), leur préchargement sur votre page d'accueil risque donc de ne pas être la solution. Dans ce cas, je ferais: // enregistre la maçonnerie mais ne la place pas encore dans la file d'attente wp_register_script ('maçonnerie', get_template_directory_uri (). '/Assets/js/masonry.min.js', [], 1.0, true) ;
// foo.js is my implementation of masonry.js
wp_register_script( 'foo.js', get_template_directory_uri() . '/assets/js/masonry.min.js', [ 'masonry' ], 1.0, true );
// in bar.js I keep functions used all over my page so I enqueue it everywhere immediately
wp_enqueue_script( 'bar.js', get_template_directory_uri() . '/assets/js/masonry.min.js', [], 1.0, true );
// masonry.js and foo.js can wait until the user reaches my less popular subpage as it won't be needed most of the time
if ( is_post_type_archive( 'unpopular-posts' ) ){
wp_enqueue_script( 'foo.js' );
}
Un échange rapide avec @janh dans le cadre de ma réponse précédente m'a incité à réfléchir à une approche différente. J'irais quand même avec la minimisation de toutes les bibliothèques tierces dans un fichier de paquet séparé (bundlejs
), puis avec la variable globale $wp_scripts
(le crédit pour cette idée va à ce fil )
Cela ne sera jamais entièrement automatisé - comme Janh l'a remarqué, il est impossible de prédire comment d'autres personnes appelleraient les scripts dans leurs plugins ou leurs thèmes. Dans ma fonction, j'utilise un tableau de noms de script que contient mon fichier de paquet. Pour doubler les chances de doublons possibles, j'ai également ajouté la prise en charge des noms de fichier de script au lieu des poignées uniquement.
Gardez à l’esprit que certains scripts d’administrateur ne doivent absolument pas être touchés (voir codex )
La solution est assez crue, je suis sûr qu’elle peut être perfectionnée de nombreuses façons, mais elle pourrait certainement utiliser un peu de refactoring et la prise en charge du cache WP. De plus, je ne suis pas sûr de l’impact sur les performances dans les cas réels. Mais c'est ici que vous avez une idée générale et peut-être une inspiration:
function switch_dependencies_to_bundle(){
global $wp_scripts;
/**
* array of scripts that our bundle file contains - can be either script name or handle name
* it's never going to be bulletproof tho', as plugin authors can change file names, i.e.
* include other version of script
*/
$bundled = [
'jquery',
'masonry',
'masonry-js',
'masonry.js',
'masonry.min.js', //we can use file name too
'backbone',
'backbone.min.js'
];
$deps_to_remove = [];
// register our bundle script
wp_register_script( 'bundlejs', get_template_directory_uri() . '/assets/js/bundle.min.js', [], '1.0.0', true );
wp_enqueue_script( 'bundlejs' );
// get registered scripts that our bundle file would duplicate
foreach( $wp_scripts->registered as $handle => $script ){
$file_name = substr( $script->src , strrpos( $script->src, "/" ) + 1 );
if ( in_array( $handle, $bundled, true ) || in_array( $file_name, $bundled, true ) ){
$deps_to_remove[] = $handle;
}
}
//get rid of redundant scripts with deregister and dequeue.
//NOTE: does not work for some admin scripts, see codex
foreach( $deps_to_remove as $script ){
wp_deregister_script( $script );
wp_dequeue_script( $script );
}
// take care of remaining scripts' dependencies (they wouldn't load with deps missing)
// add our bundle as dependency, as it contains the same scripts that we just removed
foreach( $wp_scripts->registered as $script ){
if ( ! empty( array_intersect( $deps_to_remove, $script->deps ) ) ) {
$script->deps[] = 'bundlejs';
$script->deps = array_diff( $script->deps, $deps_to_remove );
}
}
}
// load the function with high priority so it kickes in after other plugins registered their scripts
add_action('wp_enqueue_scripts', 'switch_dependencies_to_bundle', 9999);