web-dev-qa-db-de.com

wp_register_script mehrere identifikatoren?

Um eine schlechte Leistung mit mehreren <script> -Tags zu vermeiden, führe ich regelmäßig eine Verkettung von Skripten durch und erstelle eine einzige bundle.min.js-JS-Datei und einen einzigen 'jsbundle'-Bezeichner.

Das Problem ist, dass Dinge, die nachträglich hinzugefügt werden, wie Plugins, von einer oder mehreren registrierten Bibliotheken abhängen können, die vorhanden sind, jedoch im generischen 'jsbundle' gepackt sind.

Gibt es eine Möglichkeit, Wordpress darüber zu informieren, dass 'jsbundle' impliziert, zum Beispiel 'jquery', 'backbone', ..., damit 1) die Ressource nicht zweimal geladen wird 2) Dinge nicht aufgrund einer unerfüllten Abhängigkeit fehlschlagen?

Ich habe es mit der Quelle von wp_register_script versucht, WP_Scripts() class gefunden und versucht, WP über verfügbare Skripte zu "lügen", aber kein Glück.

2
Miloshio

Gehen Sie folgendermaßen vor, damit die JavaScript-Bibliotheken nicht geladen werden, da Sie bereits ein Bundle davon erstellt haben:

Unter Berücksichtigung der folgenden üblichen Warteschlange:

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

nehmen wir an, Sie haben die folgenden Bibliotheken in Ihrem Bundle (mit einer Auflistung der Handles):

  1. jquery
  2. backbone
  3. colorpicker
  4. bootstrap_js

1,2,3 sind bereits im Kern, 4 ist ein Drittanbieter, Sie haben alle 4 gebündelt, weil Sie nicht möchten, dass die 4 als separate Ressourcen geladen wird.

Sie müssen sich abmelden (wenn sie registriert sind, sind die Kernbibliotheken bereits registriert) und jede einzelne davon registrieren, jede einzelne der Bibliotheken, die sich in Ihrem Bundle befinden:

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

der Schlüssel hier ist, den $src als FALSE zu setzen, damit das registrierte Skript ein Alias ​​ist. Überprüfen Sie diese Zeile im Kerncode:

// A single item may alias a set of items, by having dependencies, but no source.
if ( ! $obj->src ) {
   return true;
}

was aktuell jquery macht, wenn jquery als Abhängigkeit gesetzt wird, lädt es jquery nicht, es lädt jquery-core und jquery-migrate, dies ist das registrierte Objekt für 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) {
  }
}

bundle_js wird also geladen, wenn ein Skript als Abhängigkeit von einer der Bibliotheken (jquery, backbone, colorpicker) vorliegt, und es wird einmal geladen, da die Logik in WP_Dependencies prüft, ob es sich bereits im Array queue befindet.

Wenn Sie überprüfen möchten, ob ein Skript bereits registriert ist, verwenden Sie:

global $wp_scripts;
$wp_scripts->query('jquery'); //jquery as example handle

es gibt ein WP_dependency Objekt zurück, wenn es registriert ist, false, wenn es nicht registriert ist.

Einige Links zum besseren Verständnis:
class.wp-dependencies.php
class.wp-scripts.php
functions.wp-scripts.php

4
David Lee

Die von Alexander vorgeschlagene Lösung sieht vernünftig aus. Sie können alle minimierten Abhängigkeiten (in meinem Beispiel libs.js) in einer Datei und Ihre Skripte in der zweiten Datei wie folgt speichern:

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

Obwohl das Bündeln von Skripten eine bekannte Methode zur Optimierung der Seitenladegeschwindigkeit ist und die meiste Zeit eine gute Idee ist, ist dies möglicherweise nicht immer die leistungsfähigste Lösung. Ich würde immer einige andere Optionen in Betracht ziehen und entscheiden, was für einen bestimmten Anwendungsfall am besten funktioniert.

CDN

Möglicherweise möchten Sie eine der verfügbaren CDNs für Ihre Bibliotheken von Drittanbietern verwenden, um alle Vorteile zu nutzen, die in in dieser Antwort aufgeführt sind.

Z.B. Wenn Sie das CDN von Google oder Facebook verwenden, besteht eine große Chance, dass Ihre Besucher bereits beliebte Skripts in ihren Browsern gespeichert haben und diese nicht erneut herunterladen müssen.

In diesem Fall wird dieser Vorteil durch das Bündeln von Skripts von Drittanbietern zunichte gemacht, und das gesamte Bundle muss heruntergeladen werden, auch wenn der Benutzer einen Teil davon bereits im Cache des Browsers gespeichert hat.

Sie können Skripts aus CDN mit wp_enqueue_script() einfach in die Warteschlange stellen. Lassen Sie dazu den Parameter $ver weg, da Sie das zwischengespeicherte Skript nicht aktualisieren möchten:

wp_enqueue_script( 'jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js', [], null, true );

Bedingte Tags

Das andere, was ich in Betracht ziehen würde, ist, mehr Skripte zu registrieren und sie nur auf Seiten aufzurufen, auf denen sie tatsächlich verwendet werden. Dies funktioniert besonders gut, wenn Sie Ihre Skripte häufig aktualisieren.

Wenn Sie alle Skripte in einem Paket behalten, müssen Sie den Cache für das gesamte Skript leeren, um eine kleine Änderung vorzunehmen. Manchmal ist es möglicherweise besser, Teile Ihrer Skripte getrennt zu halten, sodass Sie die Version nur für den Teil ändern können, den Sie tatsächlich bearbeitet haben.

Nehmen wir an, ich verwende foo.js auf meiner Homepage und dort ist nicht viel los, so dass ich nicht vorhabe, es bald zu ändern, aber gleichzeitig habe ich ein kompliziertes bar.js-Skript, das ich oft warten und aktualisieren muss. In diesem Fall ist es möglicherweise besser, Skripte separat zu registrieren.

Außerdem werden einige Ihrer Bibliotheken möglicherweise nur auf Unterseiten verwendet, die nicht sehr häufig besucht werden (sagen wir, ich verwende masonry auf einer weniger beliebten Unterseite). Daher ist das Vorabladen dieser Bibliotheken auf Ihrer Homepage möglicherweise nicht der richtige Weg. In diesem Fall würde ich Folgendes tun: // Mauerwerk registrieren, es aber noch nicht in die Warteschlange stellen wp_register_script ('Mauerwerk', 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' );
}
0
Levi Dulstein

Der schnelle Austausch mit @janh unter meiner vorherigen Antwort hat mich dazu inspiriert, über einen anderen Ansatz nachzudenken. Ich würde weiterhin alle Bibliotheken von Drittanbietern in eine separate Bundle-Datei (bundlejs) minimieren und dann mit der globalen $wp_scripts-Variablen arbeiten (die Idee stammt von this thread ).

Es wird niemals vollständig automatisiert - wie Janh bemerkte, ist es unmöglich vorherzusagen, wie andere Leute die Skripte in ihren Plugins oder Themes aufrufen würden. In meiner Funktion verwende ich ein Array von Skriptnamen, die meine Bundle-Datei enthält. Um die Wahrscheinlichkeit zu verdoppeln, dass mögliche Duplikate gefunden werden, habe ich auch die Unterstützung für Skriptdateinamen anstelle von nur Handles hinzugefügt.

Denken Sie daran, dass einige Admin-Skripte überhaupt nicht angerührt werden sollten (siehe codex ).

Die Lösung ist ziemlich roh, ich bin mir sicher, dass sie in vielerlei Hinsicht perfektioniert werden kann. Sie könnte definitiv eine Umgestaltung und WP Cache-Unterstützung gebrauchen. Ich bin mir auch nicht sicher, wie es die Leistung im realen Fall beeinflusst. Aber es ist für Sie da, um sich einen Überblick zu verschaffen und vielleicht etwas Inspiration zu finden:

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);
0
Levi Dulstein