WordPress-Optimierung ohne „ReferenceError jQuery is not defined“

cat 164426
Bildquelle: Pixabay, PublicDomainPictures

Javascript nach dem DOM zu laden ist eine der wichtigsten Website-Optimierungs-Regeln, denn Ressourcen einer Website werden in der Reihenfolge ausgeführt in der sie eingebunden sind.

Die Standardposition der Skripte in WordPress ist der Headbereich. Hier ist meist auch jQuery zu finden. Falsch eingebundene oder Inline-jQuery-Funktionen könnten ansonsten nicht ausgeführt werden, erkennbar an der Fehlermeldung ReferenceError: jQuery is not defined.

inline script
Dieses Testszenario war Auslöser für den Artikel

Eigentlich sollte es Inline-Javascript in WordPress Komponenten gar nicht geben. Die Realität entspricht dem allerdings nicht immer. Vermeidet man solche und Komponenten, die ihre Skripte bereits im Head einbinden, wird das Verschieben der Ressource in den Footer der Site funktionieren und keine Konflikte erzeugen.

Erreicht wird das durch Einfügen des Snippets in der functions.php.

add_action( 'wp_enqueue_scripts', 'move_jquery_to_footer' );
function move_jquery_to_footer() {
    if ( !is_customize_preview() ) {
        wp_script_add_data( 'jquery', 'group', 1 );
        wp_script_add_data( 'jquery-core', 'group', 1 );
        wp_script_add_data( 'jquery-migrate', 'group', 1 );
    }
}

Eigene Skripte werden so eingebunden, dass sie erst im Footer geladen werden, wofür das letzte Argument sorgt, wenn es true ist:

wp_register_script( $handle, $src, $deps, $ver, $in_footer );

Beispiel:

wp_register_script( 'einmaliger-name', get_theme_file_uri( '/js/datei.js' ), array('jquery'), '1.0', true );

Ein korrekt eingebundenes Skript ist mit einer Angabe zu seinen Abhängigkeiten versehen, sodass WordPress – ganz egal, an welcher Stelle vorgesehen ist, die Skripte zu laden – auf jeden Fall zuerst laden wird, was das abhängige Skript braucht um zu funktionieren. Das kann dazu führen, dass jQuery trotz der Maßnahme die es verschieben soll, im Head geladen wird, wenn ein Skript es dort bereits anfordert.

Sind Plugins aktiv, die ihre Skripte im head einbinden, was immer der Fall ist, wenn es nicht explizit anders entschieden wird, ist das defer-Attribut eine potentielle Alternative. Es sorgt in nachfolgender Funktion dafür, das mit wp_enqueue_script eingebundenen externen Ressourcen nach dem Laden der Seite ausgeführt werden. Nur Inline-Skripte darf er keine geben, da sich das ebenfalls fehlerhaft auswirken würde.

function pppf_defer_scripts( $tag, $handle, $src ) {
     if ( !is_admin() && !is_customize_preview() ) {	
         $tag = '<script type="text/javascript" src="' . $src . '" defer="defer"></script>' . "\n";
     }

    return $tag;
}
add_filter( 'script_loader_tag', 'pppf_defer_scripts', 10, 3 );

Ggf. kann selektiver verfahren werden (nur bestimmte Skripte einbinden oder bestimmte Skripte ausschließen, dafür empfiehlt sich dann vielleicht ein Plugin).

Im Quelltext bleibt zwar alles an derselben Stelle, das Attribut legt jedoch fest, dass die Skripte erst ausgeführt werden, nachdem die Seite geladen wurde. Vorausgesetzt, kein Inline-Skript steht dem entgegen, hat defer potentiell den Optimierungseffekt wie das Verschieben von Skripten in den Footer.

Skripte asynchron laden

Das Attribut async sorgt hingegen dafür, dass das Laden der Seite weitergeht, während das Skript aber bereits ausgeführt wird, so dass etwaige Inline-Skripte wohl funktionieren würden. Geeignet ist das Attribut allerdings nur für unabhängige externe Ressourcen (z.B. Analytics). Als allgemeine Performance-Maßnahme für alle Skripte ist es hingegen keine sichere Option. Die Skripte werden ausgeführt, sobald sie geladen sind. Kleinere Skripte sind schneller verfügbar als große, sodass der Titelkonflikt wieder zuschlägt, da jQuery hinterherhinkt.

function pppf_async_scripts( $tag, $handle, $src ) {
    if ( 'my-independend-script' == $handle ) {	
        $tag = '<script type="text/javascript" src="' . $src . '" async="async"></script>' . "\n";
    }

    return $tag;
}
add_filter( 'script_loader_tag', 'pppf_async_scripts', 10, 3 );

Wird eine Komponente mit Inline-Javascript verwendet oder eine die ihre Skripte ohne Angabe von Abhängigkeiten einbindet, gibt es zwei Optionen damit umzugehen:

  1. auf performancebewusstes Laden von Skripten verzichten oder
  2. die Komponente(n) ermitteln und deaktivieren oder austauschen

Wenn es sich nicht vermeiden lässt (z.B. Ads-Integration oder ähnliches) Inline-Javascript einzusetzen, man aber selbst die Kontrolle über den Code hat, das Skript in die Funktion addEventListener einfassen.

window.addEventListener("DOMContentLoaded", function() {
 // js - stuff
});

Hinweis: Nach Maßnahmen wie hier beschrieben oder anderen die Einfluss auf die Dateiladefolge haben sind gründliche Tests erforderlich um Javascriptfehler auszuschließen. Nach der Aktivierung jeder neuen Komponente ist eine erneute Prüfung angebracht.

Bitte Kommentarfunktion nicht für Supportanfragen nutzen. Dem kann hier nicht entsprochen werden. Die Angabe einer E-Mail-Adresse und eines Namens ist nicht erforderlich. Einen (Spitz)-Namen zu nennen wäre aber doch nett.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Hinweis: Sowohl angegebener Name als auch E-Mail-Adresse (beides ist optional, dafür werden alle Kommentare vor Veröffentlichung geprüft) werden dauerhaft gespeichert. Du kannst jeder Zeit die Löschung Deiner Daten oder / und Kommentare einfordern, direkt über dieses Formular (wird nicht veröffentlicht, und im Anschluss gelöscht), und ich werde das umgehend erledigen. – Mit hinterlassenen Kommentaren hinterlegte IP-Adressen werden nach zwei Monaten automatisch gelöscht

publicly queryable