Passa le opzioni alle importazioni del modulo ES6


144

È possibile passare le opzioni alle importazioni ES6?

Come traduci questo:

var x = require('module')(someoptions);

a ES6?


Non sei sicuro che ci sia, c'è un'API per il caricamento dei moduli, o almeno ce n'era in qualche momento, che ha usato qualcosa del genere System.import(module), non sei sicuro che ciò permetta o meno argomenti, probabilmente qualcuno che sa di più su ES6 lo fa?
adeneo,

C'è una soluzione proposta per questo, per la quale ci sono già implementazioni in node.js (tramite un plug-in) e webpack: 2ality.com/2017/01/import-operator.html
Matt Browne

Risposte:


104

Non c'è modo di farlo con una singola importistruzione, non consente invocazioni.

Quindi non lo chiameresti direttamente, ma puoi praticamente fare lo stesso come fanno i commonjs con le esportazioni predefinite:

// module.js
export default function(options) {
    return {
        // actual module
    }
}

// main.js
import m from 'module';
var x = m(someoptions);

In alternativa, se usi un caricatore di moduli che supporta promesse monadiche , potresti essere in grado di fare qualcosa del genere

System.import('module').ap(someoptions).then(function(x) {
    
});

Con il nuovo importoperatore potrebbe diventare

const promise = import('module').then(m => m(someoptions));

o

const x = (await import('module'))(someoptions)

tuttavia probabilmente non vuoi un'importazione dinamica ma statica.


7
Grazie, vorrei che ci fosse una import x from 'module' use someoptions;specie di sintassi
Fabrizio Giordano,

1
@Fabrizio: se ci pensassi oltre, non sarebbe davvero utile. Funzionerebbe solo se il modulo esporta una funzione e probabilmente non dovrebbe essere consentito se abbiamo chiamato import (es import {x, y} from 'module'.). Quindi quale dovrebbe essere la sintassi se voglio passare più argomenti? O diffondere una serie di argomenti? È un caso d'uso ristretto e sostanzialmente stai cercando di aggiungere una sintassi diversa per una chiamata di funzione, ma abbiamo già chiamate di funzione che ci consentono di affrontare tutti gli altri casi.
Felix Kling,

3
@FelixKling Sono completamente d'accordo con te. Stavo convertendo una vecchia webapp express e ho riscontrato che var session = require('express-session'); var RedisStore = require('connect-redis')(session);mi chiedevo solo se esistesse una soluzione a una riga. Riesco a sopravvivere totalmente dividendo il compito del RedisStore in 2 righe :)
Fabrizio Giordano,

@FabrizioGiordano: potrei immaginare qualcosa di simile import {default(someoptions) as x} from 'module'a ES7, se ce n'è davvero bisogno.
Bergi,

2
Per l' session/ connect-redisesempio, mi è stato immaginando sintassi simile a questo: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Jeff Handley,

24

Concetto

Ecco la mia soluzione con ES6

In linea con la risposta di @ Bergi, questo è il "modello" che utilizzo quando creo importazioni che richiedono parametri passati per le classdichiarazioni. Questo è usato su un framework isomorfo che sto scrivendo, quindi funzionerà con un transpiler nel browser e in node.js (che uso Babelcon Webpack):

./MyClass.js

export default (Param1, Param2) => class MyClass {
    constructor(){
        console.log( Param1 );
    }
}

./main.js

import MyClassFactory from './MyClass.js';

let MyClass = MyClassFactory('foo', 'bar');

let myInstance = new MyClass();

Quanto sopra verrà emesso fooin una console

MODIFICARE

Esempio del mondo reale

Per un esempio del mondo reale, sto usando questo per passare in uno spazio dei nomi per accedere ad altre classi e istanze all'interno di un framework. Poiché stiamo semplicemente creando una funzione e passando l'oggetto come argomento, possiamo usarlo con la nostra dichiarazione di classe likeo:

export default (UIFramework) => class MyView extends UIFramework.Type.View {
    getModels() {
        // ...
        UIFramework.Models.getModelsForView( this._models );
        // ...
    }
}

L'importazione è un po 'più complicata e automagicalnel mio caso dato che si tratta di un intero framework, ma essenzialmente questo è ciò che sta accadendo:

// ...
getView( viewName ){
    //...
    const ViewFactory = require(viewFileLoc);
    const View = ViewFactory(this);
    return new View();
}
// ...

Spero che aiuti!


Poiché tutti i moduli importati sono classi, perché non passare il parametro quando si crea un'istanza della classe?
jasonszhao,

1
@jasonszhao La cosa più importante da notare qui è che la classe MyViewestende alcuni elementi disponibili nello spazio dei nomi del framework. Sebbene sia assolutamente possibile passarlo semplicemente come parametro alla classe, dipende anche da quando e dove la classe viene istanziata; la portabilità è quindi interessata. In pratica, queste classi possono essere consegnate ad altri framework che possono istanziarle in modo diverso (ad es. Componenti React personalizzati). Quando la classe si trova al di fuori dell'ambito del framework, può comunque mantenere l'accesso al framework quando viene istanziata a causa di questa metodologia.
Girevole

@Swivel Per favore, ho bisogno di aiuto con un problema simile: stackoverflow.com/questions/55214957/…
TSR

12

Basandosi sulla risposta di @ Bergi per usare il modulo di debug usando es6 sarebbe il seguente

// original
var debug = require('debug')('http');

// ES6
import * as Debug from 'debug';
const debug = Debug('http');

// Use in your code as normal
debug('Hello World!');

4

Credo che tu possa usare i caricatori di moduli es6. http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});

3
Ma dove finisce il risultato di m(youroptionshere)? Suppongo che potresti scrivere System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... ma non è molto chiaro.
Stijn de Witt,

2
Wow, non posso credere che non ci sia un modo elegante per farlo in E6. Questo è il modo in cui scrivo principalmente moduli.
Robert Moskal,

3

Devi solo aggiungere queste 2 righe.

import xModule from 'module';
const x = xModule('someOptions');

1
Questo è semplicemente passare parametri a una funzione che hai importato e che stai chiamando. Non passa alcuna opzione al modulo da cui lo importi . xModuleè fuorviante qui. Quello che hai effettivamente è import func from 'module'; func('someOptions');.
Dan Dascalescu il

1

Sono atterrato su questa discussione cercando qualcosa di simile e vorrei proporre una sorta di soluzione, almeno per alcuni casi (ma vedi Nota sotto).

Caso d'uso

Ho un modulo che esegue immediatamente una logica di istanza al momento del caricamento. Faccio non piace chiamare questa logica init all'esterno del modulo (che è la stessa chiamata new SomeClass(p1, p2)o new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })e simili).

Mi piace il fatto che questa logica di init verrà eseguita una volta, una specie di flusso di istanza singolare, ma una volta per un contesto parametrico specifico.

Esempio

service.js ha al suo scopo molto basilare:

let context = null;                  // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));

Il modulo A fa:

import * as S from 'service.js';     // console has now "initialized in context root"

Il modulo B fa:

import * as S from 'service.js';     // console stays unchanged! module's script runs only once

Fin qui tutto bene: il servizio è disponibile per entrambi i moduli ma è stato inizializzato solo una volta.

Problema

Come farlo funzionare come un'altra istanza e iniziarsi di nuovo in un altro contesto, diciamo nel Modulo C?

Soluzione?

Questo è ciò a cui sto pensando: usa i parametri della query. Nel servizio aggiungeremo quanto segue:

let context = new URL(import.meta.url).searchParams.get('context');

Il modulo C farebbe:

import * as S from 'service.js?context=special';

il modulo verrà reimportato, verrà eseguita la logica di inizializzazione di base e vedremo nella console:

initialized in context special

Nota: io stesso consiglierei di NON praticare molto questo approccio, ma di lasciarlo come ultima risorsa. Perché? Il modulo importato più di una volta è più un'eccezione che una regola, quindi è un comportamento inaspettato e come tale può confondere un consumatore o addirittura rompere i suoi paradigmi "singleton", se presenti.


0

Ecco la mia opinione su questa domanda usando il modulo di debug come esempio;

Nella pagina npm di questo modulo, hai questo:

var debug = require ('debug') ('http')

Nella riga sopra, una stringa viene passata al modulo che viene importato, per la costruzione. Ecco come faresti lo stesso in ES6


import {debug as Debug} da 'debug' const debug = Debug ('http');


Spero che questo aiuti qualcuno là fuori.


Perché pubblicare una risposta che duplica una già pubblicata ?
Dan Dascalescu il

1
Colpa mia. Non ho mai visto il post menzionato. Ho appena guardato la domanda e l'ho presa a pugni. Grazie per avermelo segnalato.
Akinwale Folorunsho Habib,

Prego. Puoi anche eliminare la risposta duplicata, se lo desideri.
Dan Dascalescu,
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.