In „normalem“ JavaScript auf Objekte aus Modulen zugreifen
Samuel fiedler
- html
- javascript
0 Rolf B
Hallo an alle!
Ich habe mich heute gefragt, ob ich auf von einem Modul exportierte Klassen in normalem JavaScript zugreifen kann. Beispiel:
<script type="module">
export default function test() {
return 42;
}
</script>
<script>
console.log(test());
</script>
Das funktioniert leider nicht. Gibt es da irgendeine Möglichkeit, die Funktion test verfügbar zu machen?
Au revoir,
Samuel Fiedler
Hallo Samuel,
Du kannst auf Exporte von Modul A nur zugreifen, wenn Modul B das Modul A importiert.
Dass das bei inline-Scripten geht, scheint mir zweifelhaft, das habe ich noch nicht gesehen und finde auch spontan keine Syntax dafür.
Das hier geht jedenfalls nicht:
<script type="module">
include { blub } from "#test";
blub();
</script>
<script id="test" type="module">
export function blub() {
console.log("Plitsch Platsch");
}
</script>
Nach meiner Kenntnis muss alles, was Du importierst, von extern kommen.
Rolf
Hallo Rolf B!
Nach meiner Kenntnis muss alles, was Du importierst, von extern kommen.
OK. Ich habe das Gleiche auch schon befürchtet.
Mir fiel aber gerade eben noch ein, dass man doch in einem Modul einen Event-Listener an ein Element hängen könnte. Kann man irgendwie auf die Event-Listener zugreifen, sodass man diese Funktionen hat?
Au revoir,
Samuel Fiedler
Hallo Samuel fiedler!
Ich habe jetzt doch eine Möglichkeit gefunden:
<!DOCTYPE html>
<script type="module">
function test() {
console.log("Hello World!");
return 0;
}
window.addEventListener('DOMContentLoaded', function() {
window.test = test;
});
</script>
<script>
function delay(n) {
return new Promise(function(resolve) {
setTimeout(resolve, n * 1000);
});
}
window.addEventListener('DOMContentLoaded', async function() {
await delay(0.001);
window.test();
});
</script>
Man muss also einen Event Listener irgendwo dranhängen, der die Funktion in ein beliebiges globales Objekt stellt. Nachdem das getan ist, funzt es.
Au revoir,
Samuel Fiedler
Hallo Samuel,
ja, so was ähnliches habe ich gerade auch zusammengefrickelt. Wenn man aus einem Modul heraus etwas globales bereitstellen will, muss man es an ein globales Objekt anpappen. Das kann das window-Objekt sein, es könnte auch eine vertrauliche private Eigenschaft an einem HTML Element sein.
Was Du gemacht hast, ist eine zeitliche Abfolge zu erzwingen, über die Millisekundenpause. Wenn das ECMAScript-Modul intern ist, ist das machbar. Kommt es von extern, dürfte das nicht reichen. Jegliche fixe Zeitspanne kann nur falsch sein.
Lass uns dafür das Timing von Modulen anschauen.
Heißt also:
<script type="module">
window.test = function() { alert("test"); };
</script>
<script>
test();
</script>
kann deshalb nicht funktionieren, weil das Modul deferred läuft und die Zuweisung an window.test erst erfolgt, wenn der zweite Scriptblock schon durch ist. Man könnte auf die Idee kommen, dem ECMAScript-Modul eine ID zu geben und sich auf das load-Event des Scriptelements zu registrieren, um zu wissen, wann das Modul da ist - das hilft aber nichts, weil load bei einem inline-Script nicht gefeuert wird. Und ein afterscriptexecute-Event gibt's nicht - nicht offiziell, das ist Firefox-spezial.
Das hier
<script type="module">
window.test = function() { alert("test"); };
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
test();
});
</script>
würde dagegen funktionieren, weil DOMContentLoaded erst nach Verarbeitung aller defer-Scripte läuft.
Aber ich mach's trotzdem rot. Ein ECMAScript-Modul, das vorsätzlich Dinge in den globalen Scope ballert, ist nicht im Sinne des Erfinders.
Die sinnvolle Lösung wäre, das ganze Projekt als ECMAScript-Modulbaum zu schreiben, mit vielen kleinen überschaubaren Modülchen, und diese für den Produktivbetrieb zu einer Datei zu bündeln (bspw. mit Webpack).
Rolf