ES6: Bedingte und dynamische Importanweisungen

85

Bedingt

Ist es möglich, bedingte Importanweisungen wie unten zu haben?

if (foo === bar) {
    import Baz from './Baz';
}

Ich habe das oben genannte versucht, erhalte aber beim Kompilieren den folgenden Fehler (von Babel).

'import' and 'export' may only appear at the top level

Dynamisch

Ist es möglich, dynamische Importanweisungen wie unten zu haben?

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        import Baz from `./${foo}`;
    }
}

Das Obige erhält beim Kompilieren den gleichen Fehler von Babel.

Ist das möglich oder fehlt mir etwas?

Argumentation

Der Grund, warum ich dies versuche, ist, dass ich viele Importe für eine Reihe von "Seiten" habe und sie einem ähnlichen Muster folgen. Ich möchte meine Codebasis bereinigen, indem ich diese Dateien mit einer dynamischen for-Schleife importiere.

Wenn dies nicht möglich ist, gibt es dann eine bessere Möglichkeit, eine große Anzahl von Importen in ES6 zu verarbeiten?

Enijar
quelle
1
Kann in einem solchen Fall keine Vererbung verwendet werden? verwenden super, um bestimmte anzurufen.
Jai
Ich verwende bereits Vererbung, aber diese "Seiten" enthalten "seitenspezifische" Logik. Ich habe eine Basisklasse "Seite", die alle erweitert ist, aber dies reicht nicht aus, um die große Anzahl von Importen zu bereinigen, die ich habe.
Enijar
1
@zerkms: Sie werden nicht aus Blöcken herausgezogen - sie sind Syntaxfehler.
Bergi
Mögliches Duplikat des Importnamens der ES6-Variablen in node.js ?
Bergi

Antworten:

54

Wir haben jetzt einen dynamischen Importvorschlag bei ECMA. Dies ist in Stufe 2. Dies ist auch als Babel-Preset verfügbar .

Im Folgenden finden Sie eine Möglichkeit zum bedingten Rendern gemäß Ihrem Fall.

if (foo === bar) {
    import('./Baz')
    .then((Baz) => {
       console.log(Baz.Baz);
    });
}

Dies gibt im Grunde ein Versprechen zurück. Die Auflösung des Versprechens wird voraussichtlich das Modul haben. Der Vorschlag enthält auch Elemente wie mehrere dynamische Importe, Standardimporte, Import von JS-Dateien usw. Weitere Informationen zu dynamischen Importen finden Sie hier .

thecodejack
quelle
3
Dies. Dynamische Importe sind der richtige Weg. Sie funktionieren genau wie require (), außer dass sie Ihnen eher ein Versprechen als ein Modul geben.
Superluminary
24

Sie können Ihre Abhängigkeiten nicht dynamisch auflösen, da diese importsfür die statische Analyse vorgesehen sind. Allerdings können Sie hier wahrscheinlich einige verwenden require, wie zum Beispiel:

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}
Jonathan Petitcolas
quelle
8
"Da Importe für statische Analysen gedacht sind." --- Diese Aussage ist vage. imports dienen zum Importieren und nicht zur Analyse.
Zerkms
12
@zerkms - Ich denke, sie bedeuteten, dass importAnweisungen für die statische Analyse geeignet sind. Da sie niemals bedingt sind, können Tools die Abhängigkeitsbäume einfacher analysieren.
Joe Clay
4
Mit "foo", "baz" und "bar" schwer zu verstehen - wie wäre es mit einem Beispiel aus dem wirklichen Leben?
TetraDev
1
Das stimmt nicht mehr. Dynamische Importe sind jetzt eine Sache. Siehe hier: stackoverflow.com/a/46543949/687677
Superluminary
7

Da diese Frage von Google einen hohen Stellenwert hat, ist darauf hinzuweisen, dass sich die Dinge geändert haben, seit die älteren Antworten veröffentlicht wurden.

MDN hat diesen Eintrag unter Dynamische Importe :

Das Schlüsselwort import kann als Funktion zum dynamischen Importieren eines Moduls aufgerufen werden. Auf diese Weise wird ein Versprechen zurückgegeben.

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });

// This form also supports the await keyword.
let module = await import('/modules/my-module.js');

Einen nützlichen Artikel zu diesem Thema finden Sie auf Medium .

LeeGee
quelle
1

Require löst Ihr Problem nicht, da es sich um einen synchronen Anruf handelt. Es gibt verschiedene Möglichkeiten, die alle eine Rolle spielen

  1. Fragen Sie nach dem Modul, das Sie benötigen
  2. Warten auf ein Versprechen, das Modul zurückzugeben

In ECMA Script werden verzögerte Lademodule mit SystemJS unterstützt. Dies wird natürlich nicht in allen Browsern unterstützt, daher können Sie in der Zwischenzeit JSPM oder einen SystemJS-Shim verwenden.

https://github.com/ModuleLoader/es6-module-loader

Henrik Vendelbo
quelle
1

Seit 2016 ist in der JavaScript-Welt viel vergangen, daher glaube ich, dass es Zeit ist, die aktuellsten Informationen zu diesem Thema anzubieten. Derzeit sind dynamische Importe sowohl auf Knoten als auch in Browsern Realität (nativ, wenn Sie sich nicht für den Internet Explorer interessieren, oder mit @ babel / plugin-syntax-dynamic-import, wenn Sie sich dafür interessieren).

Stellen Sie sich also ein Beispielmodul something.jsmit zwei benannten Exporten und einem Standardexport vor:

export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')

Wir können die import()Syntax verwenden, um sie einfach und sauber unter bestimmten Bedingungen zu laden:

if (somethingIsTrue) {
  import('./something.js').then((module) => {
    // Use the module the way you want, as:
    module.hi('Erick') // Named export
    module.bye('Erick') // Named export
    module.default() // Default export
  })
}

Da die Rückgabe jedoch a ist Promise, ist auch der async/ awaitsyntaktische Zucker möglich:

async imAsyncFunction () {
  if (somethingIsTrue) {
    const module = await import('./something.js')
    module.hi('Erick')
  }
}

Denken Sie jetzt über die Möglichkeiten zusammen mit der Objektzerstörungszuweisung nach ! Zum Beispiel können wir einfach nur einen der genannten Exporte für die spätere Verwendung im Speicher ablegen:

const { bye } = await import('./something.js')
bye('Erick')

Oder greifen Sie zu einem der genannten Exporte und benennen Sie ihn in etwas anderes um, das wir wollen:

const { hi: hello } = await import('./something.js')
hello('Erick')

Oder benennen Sie die exportierte Standardfunktion in etwas Sinnvolleres um:

const { default: helloWorld } = await import('./something.js')
helloWorld()

Nur eine letzte (aber nicht zuletzt) ​​Anmerkung: import() Sieht vielleicht aus wie ein Funktionsaufruf, ist aber keine Function. Es ist eine spezielle Syntax, bei der nur Klammern verwendet werden (ähnlich wie bei super()). Es ist also nicht möglich, importeiner Variablen zuzuweisen oder Dinge des FunctionPrototyps wie call/ zu verwenden apply.

Erick Petrucelli
quelle