Linuchs: mit Javascript eine externe Script-Datei laden und ausführen

problematische Seite

Moin,

in meinen Kalendern zeigte ich bisher Landkarten (z.B. OSM, Google). Damit greift eine fremde Domain auf meine Seite zu und greift Daten ab.

Das möchte ich ändern und die "Zutaten" der Landkarte, u.a. Script-Dateien, erst nach Klick durch den Besucher laden und ausführen.

Doch wohin soll ich die laden?

document.getElementsByTagName("head")[0].append('<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet-src.js" integrity="sha512-WXoSHqw/t26DszhdMhOXOkI7qCiv5QWXhH9R7CgvgZMHz1ImlkVQ3uNsiQKu5wwbbxtPzFXd1hK4tzno2VqhpA==" crossorigin=""><\/script>');
document.getElementsByTagName("head")[0].append('<script src="css/leaflet_cluster_src.js"><\/script>');

Vermutlich falscher Ort, weil der "Render" dort schon vorbeigelaufen ist.

Aber auch in die "Zukunft" kann ich es nicht platzieren, weil "remso_map" zu diesem Zeitpunkt noch nicht bekannt ist.

document.getElementById("remso_map").append('<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet-src.js" integrity="sha512-WXoSHqw/t26DszhdMhOXOkI7qCiv5QWXhH9R7CgvgZMHz1ImlkVQ3uNsiQKu5wwbbxtPzFXd1hK4tzno2VqhpA==" crossorigin=""><\/script>');
document.getElementById("remso_map").append('<script src="css/leaflet_cluster_src.js"><\/script>');

Wie geht es richtig?

Gruß, Linuchs

  1. problematische Seite

    Hallo,

    in den Beispielen zum Blogartikel werden Leaflet-Script und -css nach Zustimmung des Seitenbesuchers dynamisch nachgeladen.

    Die Leafletlizenz lässt aber zu, die Dateien selbst zu hosten.

    Damit greift eine fremde Domain auf meine Seite zu und greift Daten ab.

    Was meinst du damit?

    Gruß
    Jürgen

    1. problematische Seite

      Damit greift eine fremde Domain auf meine Seite zu und greift Daten ab.

      Was meinst du damit?

      z.B. alle Browser-Daten ($_SERVER) übermittelt bekommen, Cookies setzen und wieder lesen.

      Gruß, Linuchs

      1. problematische Seite

        Hallo,

        du meinst also, das durch das Einbinden von Ressourcen von weiteren Domains diese Zugriff auf die Daten deiner Besucher haben?

        Dagegen kannst du bei Google Maps nichts tun. Bei OSM-Karten kannst du Scripte und CSS selbst hosten (Das mache ich so). Die Kartenbilder kannst du im Prinzip auch selbst hosten, musst dich dann aber um die Aktualisierungen kümmern und viel Platz haben. Du kannst auch einen Proxy zwischenschalten, das macht mein Arbeitgeber. Behalte dann aber den Traffic im Auge.

        Gruß
        Jürgen

  2. problematische Seite

    Moin,

    in meinen Kalendern zeigte ich bisher Landkarten (z.B. OSM, Google). Damit greift eine fremde Domain auf meine Seite zu und greift Daten ab.

    Das möchte ich ändern und die "Zutaten" der Landkarte, u.a. Script-Dateien, erst nach Klick durch den Besucher laden und ausführen.

    Gucks Dir an. MFG

    1. problematische Seite

      Hallo pl,

      mein Minus, wegen "Thema verfehlt". Es geht nicht um das Nachladen von HTML Inhalten, sondern um das nachträgliche Einbinden von JavaScript-Komponenten. Das geht nicht per AJAX.

      Rolf

      --
      sumpsi - posui - clusi
      1. problematische Seite

        sondern um das nachträgliche Einbinden von JavaScript-Komponenten. Das geht nicht per AJAX.

        Das geht auch per AJAX. MFG

        PS: Deine Bewertung ist mir Wurst. Wenn Du hier jemanden beeindrucken willst, zeige Lösungen und wie Du es besser kannst!

        1. problematische Seite

          Hallo pl,

          zeige Lösungen

          done. Ich brauche leider ein paar Minuten, um längere Texte zu schreiben. Eine Schubladenkiste wie rolfrost.de habe ich nicht, und im Self-Wiki scheint zum Thema nichts zu stehen. Da scheine ich ein I im Sonderangebot gefunden zu haben.

          Dass man einem Script-Element einen per Ajax-geladenes JS-Text als Inhalt unterschieben kann, hatte ich nicht beachtet. Also ok, es geht per Ajax.

          Allerdings verzichtet man damit das integrity-Feature (oder muss es selbst implementieren). Und es ist umständlicher, den Script-Text zuerst selbst abzuholen, statt ihn vom Browser via script-Element automagisch holen zu lassen.

          Ein Vorteil von handgemachtem Ajax-Scripting ist natürlich, dass man damit die Ausführungsreihenfolge und die Abhängigkeiten in der Hand hat. Man requestet 17 Scripte in Variablen, erzeugt die Script-Elemente und fügt sie in der Reihenfolge hinzu, dass die Abhängigkeiten passen. Aber eigentlich gibt's dafür Bundling, ECMAScript-Module oder AMD Loader.

          Rolf

          --
          sumpsi - posui - clusi
          1. problematische Seite

            Das eigenliche Problem ist wie beschrieben, daß eine fremde Domain Daten abgreift. Da gehts also gar nicht um Nachladen von JS sondern darum das zu verhindern. Eine Möglichkeit ist, wie ich gezeigt habe: Die Eingabe eines Passwort. Ein Captcha würde dem Zweck auch genügen.

            Und entschuldige bitte, wie ICH eine Problemstellung hier zu verstehen habe, das möchtest Du bitteschön MIR überlassen. MFG

            1. problematische Seite

              Hallo pl,

              äh, nein? Das Problem ist, dass sie das tut, ohne dass der User zugestimmt hat. Eine Basic Authentication über eine TLS-freie Leitung zu jagen ändert das wohl nicht.

              Dass leaflet auf diverse JavaScript-Variablen zugreift, an denen es nichts verloren hat, lässt sich durch die Art der Einbindung von leaflet nicht ändern. Das geht nur durch konsequenten Einsatz des Module-Patterns im übrigen Code, und das scheint mir nach Linuchs Einleitung nicht das Thema zu sein.

              Das Problem ist ein mögliches Profiling des Users beim Laden von Leaflet und der von Leaflet genutzten Kompomenten. Ein Profiling durch das CDN, aus dem Leaflet geladen wird, lässt sich durch Eigenhosting vermeiden. Aber Leaflet greift auf weitere externe Elemente zu, und die kann Linuchs schlecht selbst hosten. Dieses Profiling ist nur mit hohem Aufwand vermeidbar (der von Jürgen erwähnte Proxy). Darum dürfte es Linuchs eher darum gehen, leaflet erst dann einzubinden, wenn der User etwas geklickt hat (d.h. die Zustimmung des Benutzers vorliegt).

              Dass leaflet die Seitendaten zur Verarbeitung bekommt, lässt sich eher schlecht vermeiden. "Hey Leaflet, zeig mir doch mal einen Kartenausschnitt und die Anzahl von Events an den gezeigten Orten" - "Mach ich gern, welche Gegend, welche Events?" - "Bitte? Das sind meine Daten, die kriegst Du nicht!" - "Also gut...".

              Und entschuldige bitte, wie ICH eine Problemstellung hier zu verstehen habe, das möchtest Du bitteschön MIR überlassen.

              Natürlich. Kein Grund, deswegen zu schreien. Und wenn ich zu einem unterschiedlichem Verständnis komme, kommentiere ich dein Verständnis. Ob ich das tue oder nicht, das möchtest Du bitte mir überlassen. Und mit etwas Glück kommen wir zu einer sinnvollen Synthese.

              Rolf

              --
              sumpsi - posui - clusi
              1. problematische Seite

                Und mit etwas Glück kommen wir zu einer sinnvollen Synthese.

                Ne. Der Zug ist 1. abgefahren und 2. ist sowas nicht im Sinne eines öffentlichen Forum. Genausowenig wie das Bewertungssystem. Aber Leute wie Du werden das nie verstehen!

                1. problematische Seite

                  Hallo pl,

                  Ne. Der Zug ist 1. abgefahren und 2. ist sowas nicht im Sinne eines öffentlichen Forum. Genausowenig wie das Bewertungssystem. Aber Leute wie Du werden das nie verstehen!

                  Bitte unterlasse deine arroganten Beleidigungen. Danke.

                  Bis demnächst
                  Matthias

                  --
                  Pantoffeltierchen haben keine Hobbys.
                  ¯\_(ツ)_/¯
              2. problematische Seite

                Hello,

                das wäre doch mal wieder ein netter Werbeslogan für den ersten April:

                | Unsere Webseiten sind garantiert TLS-frei |

                ☆grins☆

                Glück Auf
                Tom vom Berg

                --
                Es gibt nichts Gutes, außer man tut es!
                Das Leben selbst ist der Sinn.
              3. problematische Seite

                Hallo,

                Und mit etwas Glück kommen wir zu einer sinnvollen Synthese.

                ja, und wenn's schlecht läuft, dann nur zu einer Prothese.

                Ciao,
                 Martin

                --
                Ein Tag, an dem du nicht wenigstens einmal gelacht hast, ist ein verlorener Tag.
      2. problematische Seite

        Was das Bewertungssystem betrifft: Es ist unsinnig. Und es ist nicht das Erstemal daß ich auf diesen Unsinn eingehe. Ich hatte vor einiger Zeit eine konstruktive Diskussion zu diesem Thema angeregt, leider kam mir da anstelle Verständnis nur Arroganz, Haß und Mobberei entgegen. Es ist Euer Forum, nicht meins!

        1. problematische Seite

          Hallo pl,

          Was das Bewertungssystem betrifft: Es ist unsinnig.

          Nein.

          Ich hatte vor einiger Zeit eine konstruktive Diskussion zu diesem Thema angeregt,

          Ich glaube nicht. Aber du kannst gern eine konstruktive Diskussion dazu im Meta-Forum beginnen.

          leider kam mir da anstelle Verständnis nur Haß und Mobberei entgegen.

          Ich habe schon oft klargestellt, dass in diesem Forum keiner gemobbt wird. Und auch dir entgegenschlagenden Haß kann ich nicht entdecken.

          Ich mach diesen Ast hier zu.

          Bis demnächst
          Matthias

          --
          Pantoffeltierchen haben keine Hobbys.
          ¯\_(ツ)_/¯
  3. problematische Seite

    Hallo Linuchs,

    document.getElementsByTagName("head")[0]

    Du kannst auch document.head nehmen.

    .append('<script src="..." integrity="..." crossorigin=""><\/script>');

    Das kannst Du nicht nehmen. Append akzeptiert zwar auch Strings, parsed aber kein HTML. Wenn Du ein HTML Element hinzufügen willst, musst Du es mit document.createElement erzeugen und die Attribute im Script setzen. Oder Du verwendest jQuery, dem kannst Du einen HTML String übergeben und es parsed ihn.

    Du solltest übrigens nicht leaflet-src.js laden, sondern leaflet.js, das ist die minifizierte Version. Die lädt schneller. Das Gleiche gilt für das markercluster Plugin, auch da gibt es eine minifizierte Version.

    Zum Ablauf:

    In dem Moment, wo Du ein Script-Element dem <head> hinzufügst, wird es geladen und danach ausgeführt.

    Vermutlich falscher Ort, weil der "Render" dort schon vorbeigelaufen ist.

    Deswegen: Diese Annahme ist falsch. Der Ort ist korrekt. Da Du das Hinzufügen erst dann startest, wenn dein DOM geladen ist, steht das DOM und eventuelle globale Werte deiner eigenen Scripte dem nachgeladenen Script vollständig zur Verfügung. "Geographisch" befindet sind das nachgeladene Script zwar vor dem DOM, das ist in diesem Fall aber irrelevant.

    Aber auch in die "Zukunft" kann ich es nicht platzieren, weil "remso_map" zu diesem Zeitpunkt noch nicht bekannt ist.

    Warum? Wenn das Laden durch einen Button ausgelöst wird, ist das DOM geladen und remso_map sollte existieren. Aber du solltest beim head bleiben. Die Platzierung dynamisch nachgeladener Scripte ist - soweit ich weiß - egal, und im head stehen sie alle schön beieinander.

    Hinweis: Der Unterschied zwischen fest notierten Scripts und per document.head.append ist, dass die append-eten Scripts asynchron ausgeführt werden. Das ist dann relevant, wenn Du mehrere Scripte lädst und das zweite vom ersten abhängt. leaflet ist aber AMD-kompatibel, d.h. Du kannst JS Bibliotheken wie require.js einsetzen um dynamisch nachzuladen und die Abhängigkeiten zu beachten. Das macht die Sache sehr bequem (bis auf die Extra-Library, die Du einbinden und verstehen musst).

    Wenn Du keine AMD Library verwenden willst, kannst Du die beiden Scripte zusammenkopieren und von deinem Server laden. Sie folgen beide dem Modulpattern, d.h. sie sind in eine IIFE gekapselt, deshalb geht das. Zuerst leaflet, dann leaflet_cluster. Dann musst Du nur ein Script laden.

    Was nicht sicher funktioniert, ist, sich beim ersten Script-Element auf das load Event zu registrieren und im Eventhandler das Laden des zweiten Scripts anzustoßen. Dass load gefeuert wird, bedeutet nur, dass das Script geladen ist, nicht, dass es ausgeführt wurde. Es wird vermutlich funktionieren; ich kann es Dir aber nicht garantieren. Die sinnvollen Alternativen sind nach meiner Meinung ein AMD-Loader oder ein Bundle.

    Ob die Modul-Syntax von JavaScript funktioniert, weiß ich nicht. Es gibt zwar eine Modulunterstützung bei Leaflet, aber sie schreiben da nur "node.js" drüber. Ich habe nicht ausprobiert, ob sie auch als ECMAScript-Module genutzt werden können-.

    Rolf

    --
    sumpsi - posui - clusi
    1. problematische Seite

      Hallo Rolf,

      Was nicht sicher funktioniert, ist, sich beim ersten Script-Element auf das load Event zu registrieren und im Eventhandler das Laden des zweiten Scripts anzustoßen. Dass load gefeuert wird, bedeutet nur, dass das Script geladen ist, nicht, dass es ausgeführt wurde. Es wird vermutlich funktionieren; ich kann es Dir aber nicht garantieren. Die sinnvollen Alternativen sind nach meiner Meinung ein AMD-Loader oder ein Bundle.

      also bei meinem GPX-Viewer funktioniert das. Und in den Leafletbeispielen im Blog auch.

      Gruß
      Jürgen

      1. problematische Seite

        Hallo JürgenB,

        ja, bei meinen Experimenten auch. Ich habe bei Stackoverflow aber auch schon abweichende Meinungen gelesen, und weiß darum nicht, ob es bei manchen Browsern anders ist.

        Könntest Du garantieren, dass es mit einem load-Handler sauber funktioniert? Abgesehen davon, dass es das Nachbauen vorhandener Räder ist und ich es darum nicht empfehlen möchte…

        Rolf

        --
        sumpsi - posui - clusi
        1. problematische Seite

          Hallo Rolf,

          mein GPX-Viewer ist seit Jahren auf mehreren Hundert Sites im Einsatz, und ich habe bisher keine Klagen gehört.

          Welchen Scriptnachlader empfiehlst du denn?

          Gruß
          Jürgen

    2. problematische Seite

      @@Rolf B

      document.getElementsByTagName("head")[0]

      Du kannst auch document.head nehmen.

      Lies: Du solltest …

      .append('<script src="..." integrity="..." crossorigin=""><\/script>');

      Das kannst Du nicht nehmen. Append akzeptiert zwar auch Strings, parsed aber kein HTML. Wenn Du ein HTML Element hinzufügen willst, musst Du es mit document.createElement erzeugen und die Attribute im Script setzen. Oder Du verwendest jQuery, dem kannst Du einen HTML String übergeben und es parsed ihn.

      Nein. Vanilla-JavaScript kann das auch. ☞ Element​.insert​Adjacent​HTML()

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann