ES6: istruzioni di importazione dinamica e condizionale


86

Condizionale

È possibile avere istruzioni di importazione condizionali come di seguito?

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

Ho provato quanto sopra ma ricevo il seguente errore (da Babel) durante la compilazione.

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

Dinamico

È possibile avere istruzioni di importazione dinamica come di seguito?

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

Quanto sopra riceve lo stesso errore da Babel durante la compilazione.

È possibile o c'è qualcosa che mi manca?

Ragionamento

Il motivo per cui provo a farlo è che ho molte importazioni per un numero di "pagine" e seguono uno schema simile. Vorrei ripulire la mia base di codice importando questi file con un ciclo for dinamico.

Se ciò non è possibile, esiste un modo migliore per gestire un gran numero di importazioni in ES6?


1
non si può usare l'eredità in questo caso? utilizzare superper chiamare specifico.
Jai

Sto già usando l'ereditarietà, ma queste "pagine" contengono una logica specifica per "pagina". Ho una classe di "pagina" di base che si estende tutte, ma questo non è sufficiente per ripulire il vasto numero di importazioni che ho.
Enijar

1
@zerkms: non vengono tirati fuori dai blocchi - sono errori di sintassi.
Bergi


Risposte:


54

Abbiamo ora una proposta di importazioni dinamiche con ECMA. Questo è nella fase 2. Questo è disponibile anche come preset babele .

Di seguito è riportato il modo per eseguire il rendering condizionale secondo il tuo caso.

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

Questo fondamentalmente restituisce una promessa. La risoluzione della promessa dovrebbe avere il modulo. La proposta ha anche cose come importazioni dinamiche multiple, importazioni predefinite, importazione di file js ecc. Puoi trovare ulteriori informazioni sulle importazioni dinamiche qui .


3
Questo. Le importazioni dinamiche sono la strada da percorrere. Funzionano proprio come require (), tranne per il fatto che ti danno una promessa piuttosto che un modulo.
superluminaria

25

Non puoi risolvere dinamicamente le tue dipendenze, poiché importssono pensate per l'analisi statica. Tuttavia, probabilmente puoi usarne alcuni requirequi, qualcosa come:

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}

8
"poiché le importazioni sono destinate all'analisi statica." --- questa affermazione è vaga. importsono progettati per l'importazione, non per l'analisi.
zerkms

13
@zerkms - Penso che ciò che intendessero dire è che le importdichiarazioni sono pensate per essere adatte all'analisi statica - poiché non sono mai condizionali, gli strumenti possono analizzare gli alberi delle dipendenze più facilmente.
Joe Clay

4
Difficile da capire con "foo" "baz" e "bar" - che ne dici di un esempio di vita reale?
TetraDev

1
Questo non è più vero. Le importazioni dinamiche ora sono una cosa. Vedi qui: stackoverflow.com/a/46543949/687677
superluminary

7

Poiché questa domanda è molto apprezzata da Google, vale la pena sottolineare che le cose sono cambiate da quando sono state pubblicate le risposte precedenti.

MDN ha questa voce in Importazioni dinamiche :

La parola chiave import può essere chiamata come funzione per importare dinamicamente un modulo. Quando viene utilizzato in questo modo, restituisce una promessa.

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');

Un utile articolo sull'argomento è disponibile su Medium .


2

Dal 2016 sono passate molte cose nel mondo JavaScript, quindi credo che sia ora di offrire le informazioni più aggiornate su questo argomento. Attualmente le importazioni dinamiche sono una realtà sia su Node che sui browser (in modo nativo se non ti interessa IE, o con @ babel / plugin-syntax-dynamic-import se ti interessa).

Quindi, considera un modulo di esempio something.jscon due esportazioni denominate e un'esportazione predefinita:

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

Possiamo usare la import()sintassi per caricarlo in modo semplice e pulito in modo condizionale:

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
  })
}

Ma poiché il ritorno è a Promise, lo async/ awaitzucchero sintattico è anche possibile:

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

Ora pensa alle possibilità insieme all'assegnazione di destrutturazione di oggetti ! Ad esempio, siamo in grado di mettere facilmente in memoria solo una di quelle esportazioni con nome per un uso successivo:

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

O forse prendi una di quelle esportazioni denominate e rinominala in qualsiasi altra cosa che vogliamo:

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

O anche rinominare la funzione esportata predefinita in qualcosa che abbia più senso:

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

Solo un'ultima (ma non meno importante) nota: import() potrebbe sembrare una chiamata di funzione, ma non è un file Function. È una sintassi speciale che utilizza solo le parentesi (simile a ciò che accade con super()). Quindi non è possibile assegnare importa una variabile o usare cose del Functionprototipo, come call/ apply.


1

Require non risolverà il tuo problema poiché si tratta di una chiamata sincrona. Ci sono diverse opzioni e tutte coinvolgono

  1. Chiedere il modulo che ti serve
  2. In attesa di una promessa di restituzione del modulo

In ECMA Script è disponibile il supporto per i moduli di caricamento lento utilizzando SystemJS. Questo ovviamente non è supportato in tutti i browser, quindi nel frattempo puoi usare JSPM o uno shim SystemJS.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.