ES6-Module im Browser: Sind sie bereit oder nicht?

Haben Sie von der Verwendung von ES6-Modulen in einem Browser gehört? Eigentlich sind dies gewöhnliche ES6-Module. Sie gelten nur in Code für Browser.



Wenn jemand es nicht weiß - so sieht es aus.

Es gibt eine Seite index.html:

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
  
    <script type="module" src="index.mjs"></script>
    <!--     "module" -->
  </body>
</html>

Es gibt eine Datei, index.mjsdie ein mit der Seite verbundenes Modul darstellt:

import { doSomething } from './utils.mjs';

doSomething('Make me a sandwich');

Dieses Modul importiert wiederum die Funktion doSomethingaus dem Modul utils.mjs:

export const doSomething = message => {
  console.log('No.');
};

ES6-Module gibt es schon seit vielen Jahren. Und vielleicht denkst du darüber nach, sie auszuprobieren. Ich habe sie ungefähr einen Monat lang in meinem eigenen Projekt verwendet. Gleichzeitig kam ich zu dem Schluss, dass ...

Suspend!

Informationen zur Browserunterstützung für Module


Bevor ich über das spreche, was ich verstehe, schlage ich vor, einen Blick auf die Browserunterstützung für Module zu werfen. Ich schreibe dieses Material Anfang 2020, daher ist der Grad der Unterstützung für die Module zu 90% beeindruckend.


Unterstützung für Module mit Browsern laut caniuse.com,

ich bin mit diesen 90% sehr zufrieden (ich berücksichtige nicht die Bedürfnisse von 10% der Benutzer), obwohl Sie vielleicht verantwortungsbewusster sein möchten. Selbst wenn Ihr Projekt nicht für IE, UC oder Opera Mini ausgelegt ist, bedeutet diese Unterstützungsstufe, dass fast 100% Ihrer Zielgruppe problemlos mit Ihrem Projekt arbeiten können.

Die Browserunterstützung für Module ist zwar nur der Anfang. Hier möchte ich die Antwort auf drei Fragen finden, die sich zu Beginn meiner Reise zu Modulen stellten:

  • Hat die Verwendung von Modulen in Browsern irgendwelche Vorteile?
  • Was ist mit den Nachteilen?
  • Ich bin mir sicher, dass ich eine dritte Frage hatte, aber jetzt kann ich mich nicht mehr daran erinnern.

Lass es uns herausfinden ...

Was sind die Vorteile der Verwendung von Modulen in Browsern?


Das ist reines JavaScript! Keine Assembly-Projekt-Pipeline, keine 400-Zeilen-Webpack-Konfigurationsdatei, kein Babel, keine Plugins und Presets und keine zusätzlichen 45-npm-Module. Nur Sie und Ihr Code.

Das Schreiben von Code, der im Browser genau in der Form ausgeführt wird, in der er erstellt wurde, hat etwas Erfrischendes. Dies kann etwas mehr Aufwand erfordern, aber das Ergebnis ist sehr angenehm. So fahren Sie ein Auto mit einem Schaltgetriebe.

Damit. Die Vorteile von ES6-Modulen sind reines JavaScript. Dies ist das Fehlen von Assembly, Projektkonfiguration und die Ablehnung unnötiger Abhängigkeiten. Und was noch? Gibt es noch etwas?

Nein, nichts weiter.

Was sind die Nachteile der Verwendung von Modulen in Browsern?


▍Vergleich von Modulen und Bundlern


Wenn Sie überlegen, ob ES6-Module in einem Browser verwendet werden sollen, müssen Sie tatsächlich zwischen Modulen und Bundlern wie Webpack, Parcel oder Rollup wählen.

Sie können (wahrscheinlich) beide verwenden, aber in Wirklichkeit gibt es keinen Grund, das Design <script type="module">zum Laden der Bundle-Dateien zu verwenden, wenn Sie den Code über den Bundler ausführen möchten .

Ausgehend von der Annahme, dass jemand die Möglichkeit in Betracht zieht, ES6-Module anstelle eines Bundlers zu verwenden, muss er Folgendes aufgeben:

  • Minimierung des fertigen Codes.
  • Modernste JavaScript-Funktionen.
  • Syntax, die sich von der JavaScript-Syntax unterscheidet (React, TypeScript usw.).
  • Npm-Module.
  • Caching

Betrachten Sie die ersten drei Absätze dieser Liste genauer.

▍ Dateigröße


Die Größe meines Projekts, das Module verwendet, beträgt 34 ​​KB. Da ich den Projekterstellungsschritt nicht verwende, enthält der über das Netzwerk übertragene Code sehr lange Variablennamen, in denen sehr viele Kommentare enthalten sind. Darüber hinaus stellt es eine ganze Reihe kleiner Dateien dar, was in Bezug auf die Datenkomprimierung nicht sehr gut ist.

Wenn ich all dies mit Parcel in ein Bündel packe , würde sich herausstellen, dass die Größe 18 KB beträgt. Mein Casual Casio-Rechner meldet, dass dies „ungefähr die Hälfte“ des Projektcodes ist, in dem der Bundler nicht verwendet wird. Dies liegt zum Teil daran, dass Parcel Dateien minimiert, aber auch daran, dass die Materialien mit diesem Ansatz mit gzip besser komprimiert werden.

Die Datenkomprimierung macht uns auf ein anderes Problem aufmerksam: Die Art und Weise, wie Dateien organisiert sind (im Sinne der Bequemlichkeit der Entwicklung), wird direkt auf die Art und Weise übertragen, wie Dateien über das Netzwerk übertragen werden. Und die Art und Weise, wie die Dateien während der Entwicklung organisiert sind, entspricht nicht unbedingt der Art und Weise, wie Sie sie auf der Site sehen möchten. Beispielsweise können 150 Module (Dateien) bei der Arbeit an einem Projekt sinnvoll sein. Dieselben Materialien, die an den Browser übertragen werden, können in 12 Paketen organisiert werden.

Ich werde diese Idee erklären. Ich spreche nicht von der Tatsache, dass die Verwendung von Modulen bedeutet, dass Dateien nicht gebündelt und minimiert werden können (die Tatsache, dass dies nicht möglich ist, ist eine Illusion). Ich meine nur, dass es keinen Sinn macht, beides zu tun.

Ja, hier ist eine lustige Beobachtung. Bis ich diesen Abschnitt geschrieben habe, wurden in meiner Bewerbung Module verwendet (ich betone!). Ich habe Parcel installiert, um die richtige Baugruppengröße zu berechnen. Und jetzt sehe ich keinen Grund, zu normalen Modulen zurückzukehren. Nun, ist es nicht interessant!

▍Leben ohne Transpilation


Im Laufe der Jahre bin ich es sehr gewohnt, die neuesten JavaScript-Syntaxkonstrukte und das wunderbare Babel-Tool zu verwenden, mit dem sie in Code umgewandelt werden, den alle Browser verstehen. Ich habe mich so sehr daran gewöhnt, dass ich selten über Browserunterstützung nachgedacht habe (natürlich mit Ausnahme von DOM und CSS).

Als ich es zum ersten Mal versuchte type=«module», würde ich alles selbst machen. Mein Ziel waren frische Browser, daher dachte ich, ich könnte modernes JavaScript verwenden, an das ich gewöhnt bin.

Aber die Realität war nicht so rosig. Versuchen Sie, die folgenden Fragen schnell und ohne hinzuschauen zu beantworten. Unterstützt EdgeflatMap()? Unterstützt Safari destruktive Zuweisungen (Objekte und Arrays)? Unterstützt Chrome Kommas nach den letzten Funktionsargumenten? Unterstützt Firefox die Potenzierung?

Zum Beispiel musste ich nach Antworten auf diese Fragen suchen und browserübergreifende Tests durchführen. Aber ich habe das alles ewig benutzt. In jeder ausreichend großen Anwendung würde dies sehr wahrscheinlich zu Produktionsfehlern führen.

Dies bedeutet auch, dass ich die bemerkenswerteste JavaScript-Innovation seit dem Aufkommen der Array-Methode slice()- den sogenannten optionalen Sequenzoperator - nicht mehr verwenden kann . Ich habe magische Designs wie verwendetprop?.valueNur etwa einen Monat (ab dem Moment, in dem das Tool zum Erstellen einer React-App diese ohne zusätzliche Einstellungen unterstützt). Aber es ist schon unpraktisch für mich, ohne sie zu arbeiten.

▍ Caching-Lasten


Caching war für mich der größte Stolperstein. Die Tatsache, dass sich die Lösung des Caching-Problems als sehr interessant herausstellte, war der Hauptgrund, warum ich mich entschied, dieses Material zu schreiben.

Wie Sie sicher wissen, erhält jede der resultierenden Dateien bei der Verarbeitung von Materialien mit einem Bündler einen eindeutigen Namen index.38fd9e.js. Der Inhalt einer Datei mit diesem Namen ändert sich nie (nie). Daher kann es vom Browser unbegrenzt zwischengespeichert werden. Wenn eine solche Datei einmal heruntergeladen wird, müssen Sie sie nicht erneut herunterladen.

Dies ist ein erstaunliches System - es sei denn, Sie versuchen, die Antwort auf die Frage zu finden, wie der Cache geleert werden kann.

Module werden mit einem Design wie geladen<script type="module" src="index.mjs"></script>. Der Hash im Dateinamen wird nicht verwendet. Wie soll es in dieser Situation den Browser darüber informieren, wo es heruntergeladen werden soll index.mjs- aus dem Cache oder aus dem Netzwerk?

Es sollte beachtet werden, dass es fast möglich ist, den Cache akzeptabel zu machen, aber es wird einige Anstrengungen erfordern. Hierfür benötigen Sie Folgendes:

  • Sie müssen den Titel aller Antworten cache-controlauf einen Wert setzen no-cache. Unglaublicherweise bedeutet kein Cache nicht "nicht zwischenspeichern". Dies bedeutet, dass die Datei zwischengespeichert werden muss, die Datei jedoch nicht "verwendet werden sollte, um eine nachfolgende Anforderung ohne erfolgreiche Überprüfung auf dem Quellserver zu erfüllen".
  • ETag. — () , , , . , 38fd9e .
  • CDN- , . ETag . . CDN- . ( ETag) . (, , Firebase).
  • -, , « » . , , , , .

Wenn ein Besucher die Website erneut besucht, sagt der Browser daher: „Ich muss die Datei herunterladen index.mjs. Ich sehe, dass diese Datei bereits in meinem Cache vorhanden ist, ihr ETag ist 38fd9e. Ich werde diese Datei vom Server anfordern, aber ich werde ihn bitten, sie mir nur zu senden, wenn sein ETag nicht vorhanden ist 38fd9e. " Der Servicemitarbeiter fängt diese Anforderung ab, ignoriert ETag und gibt sie index.mjsaus dem Cache zurück (diese Datei wurde beim letzten Laden der Seite in den Cache verschoben). Anschließend leitet der Servicemitarbeiter die Anforderung an den Server weiter. Der Server gibt entweder eine Nachricht zurück, die besagt, dass sich die Datei nicht geändert hat, oder eine Datei, die im Cache gespeichert wird.

Meiner Meinung nach ist das alles sehr mühsam.

Wenn Sie interessiert sind, geben Sie den Code des Servicemitarbeiters ein:

self.addEventListener('fetch', e => {
  e.respondWith(
    (async () => {
      //       
      const cacheResponse = await caches.match(e.request);
      
      //   (),   
      // (ETag-    )
      fetch(e.request).then(fetchResponse => {
        caches
          .open(CACHE_NAME)
          .then(cache => cache.put(e.request, fetchResponse));
      });
      
      if (cacheResponse) return cacheResponse;
      
      return fetch(e.request);
    })()
  );
});

Ich war faul, habe also nicht studiert und nicht die neueste FetchEvent.navigationPreload- Eigenschaft verwendet . Tatsache ist, dass ich zu diesem Zeitpunkt mehr Zeit mit dem Zwischenspeichern verbracht habe als mit dem Schreiben einer Bewerbung (zu Ihrer Information habe ich 10 bzw. 11 Stunden mit diesen Angelegenheiten verbracht).

Ja, ich möchte darauf hinweisen, dass der Vorschlag der „Importkarte“ darauf abzielt, einige der oben genannten Probleme zu lösen. Es ermöglicht Ihnen, so etwas wie Mapping index.jsauf index.38fd9e.mjs zu organisieren . Um jedoch einen Hash zu generieren, benötigen Sie eine Art Assembly-Pipeline. Importkarten müssen in die HTML-Datei eingebettet werden. Dies bedeutet, dass hier ein Bundler benötigt wird ... In dieser Situation werden die Module im Browser nicht mehr benötigt.

Obwohl es interessant war, all dies zu verstehen, kann es mit der Art verglichen werden, wie ich ein Jahr lang überall auf einem Monocycle gefahren bin. Ich werde das nicht mehr tun.

Aber wahrscheinlich benutzt nicht jeder Bündler?


Ich habe dieses Material unter der Annahme geschrieben, dass jeder Code in Modulen mit Konstrukten import/exportoder schreibt requireund dann den Code mit Webpack, Grunt, Gulp oder ähnlichem in Produktionspaketen sammelt.

Gibt es Entwickler, die keine Bundler verwenden? Gibt es jemanden, der seinen JavaScript-Code in mehrere Dateien einfügt und diese ohne Bündelung an die Produktion sendet? Vielleicht bist du einer dieser Leute? Wenn ja, würde ich gerne alles über Ihr Leben wissen.

Zusammenfassung


Ich bemühe mich, alle ernsthaften Entscheidungen zu treffen, beispielsweise die Wahl zwischen Modulen und Bündlern, basierend auf den Hauptprinzipien einer effektiven Entwicklung. Das ist Produktivität und Qualität.

Leider trägt die Verwendung von Modulen in Browsern weder zum einen noch zum anderen bei.

Wenn ich morgen mit der Arbeit an einem neuen Projekt beginne, habe ich in meinem Kopf keine Frage, ob ich die gute alte App zum Erstellen und Reagieren ausführen soll. Alle anfänglichen Einstellungen dauern ungefähr 30 Sekunden, und obwohl die anfängliche Projektgröße von 40 KB etwas groß ist, spielt dies für die meisten Websites keine Rolle.

Und hier ist eine andere Situation. Angenommen, ich müsste ein wenig HTML / CSS und JavaScript für eine Art Experiment zusammenstellen, und ein solches Experiment wäre ein Projekt, das etwas mehr Dateien als einige enthält. Wenn ich während der Arbeit an diesem Projekt nicht vorhatte, das System für die Erstellung einzurichten, würde ich wahrscheinlich die Module im Browser verwenden. Und dann - wenn mir die Leistung dieses Projekts egal wäre.

Mich würde interessieren, wie Webpack und die dazugehörigen Tools mit ES6-Modulen in einem Browser funktionieren. Ich glaube, dass die Bündler in Zukunft, wenn der Vorschlag für „Importkarten“ ausreichend unterstützt wird, diese wahrscheinlich als Mechanismus zur Abstraktion unansehnlicher Hashes verwenden werden, die heute verwendet werden.

Liebe Leser! Haben Sie ES6-Module in Ihrem Browser verwendet?


All Articles