JavaScript >> Javascript-Tutorial >  >> Tags >> map

Alles, was Sie über den JavaScript-Import von Karten wissen müssen

Als ES-Module erstmals in ECMAScript 2015 eingeführt wurden, um Modulsysteme in JavaScript zu standardisieren, wurde dies implementiert, indem die Angabe eines relativen oder absoluten Pfads in Importanweisungen vorgeschrieben wurde.

import dayjs from "https://cdn.skypack.dev/[email protected]"; // ES modules

console.log(dayjs("2019-01-25").format("YYYY-MM-DDTHH:mm:ssZ[Z]"));

Dies unterschied sich geringfügig von der Funktionsweise von Modulen in anderen gängigen Modulsystemen wie CommonJS und bei der Verwendung eines Modulbündelrs wie Webpack, wo eine einfachere Syntax verwendet wurde:

const dayjs = require('dayjs') // CommonJS

import dayjs from 'dayjs'; // webpack

In diesen Systemen wurde der Importbezeichner über die Node.js-Laufzeit oder das betreffende Build-Tool einer bestimmten (und versionierten) Datei zugeordnet. Benutzer mussten nur den bloßen Modulbezeichner (normalerweise den Paketnamen) in der Importanweisung anwenden, und Bedenken hinsichtlich der Modulauflösung wurden automatisch behoben.

Da Entwickler diese Art des Importierens von Paketen bereits aus npm kannten , war ein Build-Schritt erforderlich, um sicherzustellen, dass der auf diese Weise geschriebene Code in einem Browser ausgeführt werden kann. Dieses Problem wurde durch Kartenimport gelöst. Im Wesentlichen ermöglicht es die Zuordnung von Importbezeichnern zu einer relativen oder absoluten URL, was hilft, die Auflösung des Moduls ohne die Anwendung eines Erstellungsschritts zu steuern.

So funktioniert das Importieren von Karten

<script type="importmap">
{
  "imports": {
    "dayjs": "https://cdn.skypack.dev/[email protected]",
  }
}
</script>
<script type="module">
  import dayjs from 'dayjs';

  console.log(dayjs('2019-01-25').format('YYYY-MM-DDTHH:mm:ssZ[Z]'));
</script>

Eine Importzuordnung wird über <script type="importmap"> angegeben -Tag in einem HTML-Dokument. Dieses script-Tag muss vor dem ersten <script type="module"> platziert werden Tag im Dokument (am besten im <head> ), sodass es analysiert wird, bevor die Modulauflösung ausgeführt wird. Außerdem ist derzeit nur eine Importzuordnung pro Dokument zulässig, obwohl geplant ist, diese Beschränkung in Zukunft aufzuheben.

Innerhalb des script-Tags wird ein JSON-Objekt verwendet, um alle erforderlichen Zuordnungen für die Module anzugeben, die von den Skripts im Dokument benötigt werden. Die Struktur einer typischen Importzuordnung ist unten dargestellt:

<script type="importmap">
{
  "imports": {
    "react": "https://cdn.skypack.dev/[email protected]",
    "react-dom": "https://cdn.skypack.dev/react-dom",
    "square": "./modules/square.js",
    "lodash": "/node_modules/lodash-es/lodash.js"
  }
}
</script>

In imports Objekt oben entspricht jede Eigenschaft einer Zuordnung. Die linke Seite einer Zuordnung ist der Name des Importbezeichners, während die rechte Seite die relative oder absolute URL ist, der der Bezeichner zugeordnet werden soll. Achten Sie bei der Angabe relativer URLs im Mapping darauf, dass diese immer mit / beginnen , ../ , oder ./ . Beachten Sie, dass das Vorhandensein eines Pakets in einer Importzuordnung nicht unbedingt bedeutet, dass es vom Browser geladen wird. Jedes Modul, das nicht von einem Skript auf der Seite verwendet wird, wird vom Browser nicht geladen, selbst wenn es in der Importzuordnung vorhanden ist.

<script type="importmap" src="importmap.json"></script>

Sie können Ihre Zuordnungen auch in einer externen Datei angeben und dann den src verwenden -Attribut zum Verknüpfen mit der Datei (wie oben gezeigt). Wenn Sie sich für diesen Ansatz entscheiden, stellen Sie sicher, dass die Datei mit ihrem Content-Type gesendet wird Kopfzeile auf application/importmap+json gesetzt . Beachten Sie, dass der Inline-Ansatz aus Leistungsgründen empfohlen wird und die Beispiele für den Rest dieses Artikels so dargestellt werden.

Nachdem Sie eine Zuordnung angegeben haben, können Sie den Importbezeichner wie unten gezeigt in einer Importanweisung verwenden:

<script type="module">
  import { cloneDeep } from 'lodash';

  const objects = [{ a: 1 }, { b: 2 }];

  const deep = cloneDeep(objects);
  console.log(deep[0] === objects[0]);
</script>

Es ist zu beachten, dass die Zuordnungen in einer Importzuordnung keine Auswirkungen auf URLs an Stellen wie src haben Attribut eines <script> Schild. Wenn Sie also so etwas wie <script src="/app.js"> verwenden , versucht der Browser, einen wörtlichen app.js herunterzuladen Datei unter diesem Pfad, unabhängig davon, was sich in der Importzuordnung befindet.

Einen Spezifizierer einem ganzen Paket zuordnen

Abgesehen davon, dass Sie einen Bezeichner einem Modul zuordnen, können Sie einen Bezeichner auch einem Paket zuordnen, das mehrere Module enthält. Dies geschieht durch Verwendung von Spezifiziererschlüsseln und Pfaden, die mit einem nachgestellten Schrägstrich enden.

<script type="importmap">
{
  "imports": {
    "lodash/": "/node_modules/lodash-es/"
  }
}
</script>

Diese Technik ermöglicht es Ihnen, jedes Modul im angegebenen Pfad anstelle des gesamten Hauptmoduls zu importieren, wodurch alle Komponentenmodule vom Browser heruntergeladen werden.

<script type="module">
  import toUpper from 'lodash/toUpper.js';
  import toLower from 'lodash/toLower.js';

  console.log(toUpper('hello'));
  console.log(toLower('HELLO'));
</script>

Dynamische Importkarten erstellen

Zuordnungen können auch dynamisch in einem Skript basierend auf beliebigen Bedingungen erstellt werden, und diese Fähigkeit kann verwendet werden, um ein Modul basierend auf der Merkmalserkennung bedingt zu importieren. Im folgenden Beispiel wird die richtige Datei zum Importieren unter lazyload ausgewählt Bezeichner basierend darauf, ob der IntersectionObserver API wird unterstützt.

<script>
  const importMap = {
    imports: {
      lazyload: 'IntersectionObserver' in window
        ? './lazyload.js'
        : './lazyload-fallback.js',
    },
  };

  const im = document.createElement('script');
  im.type = 'importmap';
  im.textContent = JSON.stringify(importMap);
  document.currentScript.after(im);
</script>

Wenn Sie diesen Ansatz verwenden möchten, stellen Sie sicher, dass Sie dies vor dem Erstellen und Einfügen des Import-Map-Skript-Tags (wie oben beschrieben) tun, da das Ändern eines bereits vorhandenen Import-Map-Objekts keine Auswirkungen hat.

Verbessern Sie die Cache-Fähigkeit von Skripts, indem Sie Hashes wegzuordnen

Eine gängige Technik, um statische Dateien langfristig zwischenzuspeichern, besteht darin, den Hash des Dateiinhalts in ihren Namen zu verwenden, sodass die Datei im Browser-Cache verbleibt, bis sich der Inhalt der Datei ändert. In diesem Fall erhält die Datei einen neuen Namen, sodass das neueste Update sofort in der App angezeigt wird.

Bei der traditionellen Methode zum Bündeln von Skripts kann diese Technik zu kurz kommen, wenn eine Abhängigkeit aktualisiert wird, auf die sich mehrere Module verlassen. Dadurch werden alle Dateien, die auf dieser Abhängigkeit basieren, aktualisiert, wodurch der Browser gezwungen wird, sie erneut herunterzuladen, selbst wenn nur ein einziges Zeichen des Codes geändert wurde.

Importzuordnungen bieten eine Lösung für dieses Problem, indem sie ermöglichen, dass jede Abhängigkeit separat durch eine Neuzuordnungstechnik aktualisiert wird. Angenommen, Sie müssen eine Methode aus einer Datei namens post.bundle.8cb615d12a121f6693aa.js importieren , können Sie eine Importzuordnung haben, die wie folgt aussieht:

<script type="importmap">
  {
    "imports": {
      "post.js": "./static/dist/post.bundle.8cb615d12a121f6693aa.js",
    }
  }
</script>

Anstatt Anweisungen wie

zu schreiben
import { something } from './static/dist/post.bundle.8cb615d12a121f6693aa.js'

Sie können Folgendes schreiben:

import { something } from 'post.js'

Wenn es an der Zeit ist, die Datei zu aktualisieren, muss nur die Importzuordnung aktualisiert werden. Da sich die Verweise auf seine Exporte nicht ändern, bleiben sie im Browser zwischengespeichert, während das aktualisierte Skript aufgrund des aktualisierten Hash erneut heruntergeladen wird.

<script type="importmap">
  {
    "imports": {
      "post.js": "./static/dist/post.bundle.6e2bf7368547b6a85160.js",
    }
  }
</script>

Verwendung mehrerer Versionen desselben Moduls

Es ist einfach, mehrere Versionen desselben Pakets mit Importzuordnungen anzufordern. Alles, was Sie tun müssen, ist, wie unten gezeigt, einen anderen Importbezeichner in der Zuordnung zu verwenden:

    <script type="importmap">
      {
        "imports": {
          "lodash@3/": "https://unpkg.com/[email protected]/",
          "lodash@4/": "https://unpkg.com/[email protected]/"
        }
      }
    </script>

Sie können auch denselben Importbezeichner verwenden, um durch die Verwendung von Bereichen auf verschiedene Versionen desselben Pakets zu verweisen. Dadurch können Sie die Bedeutung eines Importbezeichners innerhalb eines bestimmten Bereichs ändern.

<script type="importmap">
  {
    "imports": {
      "lodash/": "https://unpkg.com/[email protected]/"
    },
    "scopes": {
      "/static/js": {
        "lodash/": "https://unpkg.com/[email protected]/"
      }
    }
  }
</script>

Mit dieser Zuordnung werden alle Module in /static/js path verwendet den https://unpkg.com/[email protected]/ URL bei Verweis auf lodash/ Bezeichner in einem import -Anweisung, während andere Module https://unpkg.com/[email protected]/ verwenden .

NPM-Pakete mit Import Maps verwenden

Wie ich in diesem Artikel gezeigt habe, können produktionsbereite Versionen aller NPM-Pakete, die ES-Module verwenden, in Ihren Importzuordnungen über CDNs wie ESM, Unpkg und Skypack verwendet werden. Auch wenn das Paket auf NPM nicht für das ES-Modulsystem und das Importverhalten des nativen Browsers entwickelt wurde, können Dienste wie Skypack und ESM sie so umwandeln, dass sie in einer Importzuordnung einsatzbereit sind. Sie können die Suchleiste auf der Homepage von Skypack verwenden, um browseroptimierte NPM-Pakete zu finden, die sofort verwendet werden können, ohne mit einem Build-Schritt herumzuspielen.

Programmatische Erkennung der Importkartenunterstützung

Unterstützung für den Kartenimport in Browsern erkennen ist möglich, solange die Methode HTMLScriptElement.supports() unterstützt wird. Zu diesem Zweck kann das folgende Snippet verwendet werden:

if (HTMLScriptElement.supports && HTMLScriptElement.supports('importmap')) {
  // import maps is supported
}

Unterstützung älterer Browser

Import Maps ermöglicht die Verwendung von Bare-Modul-Spezifizierern im Browser, ohne von den komplizierten Build-Systemen abhängig zu sein, die derzeit im JavaScript-Ökosystem vorherrschen, aber es wird derzeit in Webbrowsern nicht allgemein unterstützt. Zum Zeitpunkt des Schreibens bieten die Versionen 89 und höher der Chrome- und Edge-Browser volle Unterstützung, aber Firefox, Safari und einige mobile Browser unterstützen diese Technologie nicht. Um die Verwendung von Importkarten in solchen Browsern beizubehalten, muss ein geeignetes Polyfill verwendet werden.

Ein Beispiel für ein Polyfill, das verwendet werden kann, ist das Polyfill ES Module Shims, das jedem Browser mit Basisunterstützung für ES-Module (ca. 94 % der Browser) Unterstützung für den Import von Karten und andere neue Modulfunktionen hinzufügt. Alles, was Sie tun müssen, ist das Skript es-module-shim in Ihre HTML-Datei einzufügen, bevor Sie das Skript für den Kartenimport verwenden:

<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

Möglicherweise erhalten Sie dennoch ein JavaScript TypeError in Ihrer Konsole in solchen Browsern nach dem Einschließen des Polyfill. Dieser Fehler kann getrost ignoriert werden, da er keine benutzerseitigen Konsequenzen hat.

Uncaught TypeError: Error resolving module specifier “lodash/toUpper.js”. Relative module specifiers must start with “./”, “../” or “/”.

Weitere Polyfills und Tools im Zusammenhang mit Importkarten finden Sie im GitHub-Repository.

Schlussfolgerung

Import-Maps bieten eine gesündere Möglichkeit, ES-Module in einem Browser zu verwenden, ohne auf den Import von relativen oder absoluten URLs beschränkt zu sein. Dies erleichtert das Verschieben Ihres Codes, ohne dass die import-Anweisung angepasst werden muss, und macht die Aktualisierung einzelner Module nahtloser, ohne die Cache-Fähigkeit von Skripten zu beeinträchtigen, die von solchen Modulen abhängen. Im Großen und Ganzen bringen Import-Maps Parität in die Art und Weise, wie ES-Module auf dem Server und in einem Browser verwendet werden.

Werden Sie Import-Maps verwenden, um Ihr aktuelles Build-System zu ersetzen oder zu ergänzen? Teilen Sie mir die Gründe für Ihre Entscheidung auf Twitter mit.

Danke fürs Lesen und viel Spaß beim Programmieren!