Übergeben Sie Optionen an ES6-Modulimporte


144

Ist es möglich, Optionen an ES6-Importe zu übergeben?

Wie übersetzen Sie das:

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

zu ES6?


Sie sind sich nicht sicher, ob Sie das können, es gibt eine Modul-Loader-API, oder zumindest gab es irgendwann eine, die so etwas wie verwendet hat System.import(module), nicht sicher, ob dies Argumente zulässt oder nicht, jemand, der mehr über ES6 weiß, wahrscheinlich?
Adeneo

Hierfür gibt es eine vorgeschlagene Lösung, für die es bereits Implementierungen in node.js (über ein Plugin) und im Webpack gibt: 2ality.com/2017/01/import-operator.html
Matt Browne

Antworten:


104

Es gibt keine Möglichkeit, dies mit einer einzelnen importAnweisung zu tun , sie erlaubt keine Aufrufe.

Sie würden es also nicht direkt aufrufen, aber Sie können im Grunde genau das tun, was commonjs mit Standardexporten macht:

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

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

Wenn Sie alternativ einen Modullader verwenden, der monadische Versprechen unterstützt , können Sie möglicherweise so etwas tun

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

Mit dem neuen importOperator könnte es werden

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

oder

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

Sie möchten jedoch wahrscheinlich keinen dynamischen, sondern einen statischen Import.


7
Vielen Dank, ich wünschte, es gäbe so etwas wie eine Art import x from 'module' use someoptions;Syntax
Fabrizio Giordano

1
@Fabrizio: Wenn du weiter darüber nachdenkst, wäre es nicht wirklich hilfreich. Es würde nur funktionieren, wenn das Modul eine Funktion exportiert und sollte wahrscheinlich nicht erlaubt sein, wenn wir Importe benannt haben (dh import {x, y} from 'module'). Wie sollte dann die Syntax lauten, wenn ich mehrere Argumente übergeben möchte? Oder eine Reihe von Argumenten verbreiten? Es ist ein enger Anwendungsfall, und im Grunde versuchen Sie, eine andere Syntax für einen Funktionsaufruf hinzuzufügen, aber wir haben bereits Funktionsaufrufe, mit denen wir alle anderen Fälle behandeln können.
Felix Kling

3
@FelixKling Ich stimme dir vollkommen zu. Ich habe eine alte Express-Webanwendung konvertiert und mich var session = require('express-session'); var RedisStore = require('connect-redis')(session);nur gefragt, ob es eine einzeilige Lösung gibt. Ich kann mit der Aufteilung der RedisStore-Aufgabe in 2 Zeilen total überleben :)
Fabrizio Giordano

@FabrizioGiordano: Ich könnte mir so etwas wie import {default(someoptions) as x} from 'module'in ES7 vorstellen , wenn es wirklich nötig ist.
Bergi

2
Für den session/ connect-redisBeispiel habe ich Syntax wie folgt worden vorstellen: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Jeff Handley

24

Konzept

Hier ist meine Lösung mit ES6

Sehr im Einklang mit der Antwort von @ Bergi ist dies die "Vorlage", die ich beim Erstellen von Importen verwende, für die Parameter für classDeklarationen übergeben werden müssen. Dies wird in einem isomorphen Framework verwendet, das ich schreibe. Es funktioniert also mit einem Transpiler im Browser und in node.js (ich verwende Babelmit 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();

Das Obige wird fooin einer Konsole ausgegeben

BEARBEITEN

Beispiel aus der realen Welt

Für ein Beispiel aus der Praxis verwende ich dies, um einen Namespace für den Zugriff auf andere Klassen und Instanzen innerhalb eines Frameworks zu übergeben. Da wir einfach eine Funktion erstellen und das Objekt als Argument übergeben, können wir es mit unserer Klassendeklaration liko verwenden:

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

Der Import ist etwas komplizierter und automagicalin meinem Fall ein komplettes Framework, aber im Wesentlichen passiert Folgendes:

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

Ich hoffe das hilft!


Da alle importierten Module Klassen sind, können Sie den Parameter beim Instanziieren der Klasse übergeben.
Jasonszhao

1
@jasonszhao Das Wichtigste dabei ist, dass die Klasse MyViewbestimmte im Namespace des Frameworks verfügbare Elemente erweitert. Es ist zwar absolut möglich, es einfach als Parameter an die Klasse zu übergeben, es hängt jedoch auch davon ab, wann und wo die Klasse instanziiert wird. Die Portabilität ist dann betroffen. In der Praxis können diese Klassen an andere Frameworks übergeben werden, die sie möglicherweise anders instanziieren (z. B. benutzerdefinierte React-Komponenten). Wenn sich die Klasse außerhalb des Framework-Bereichs befindet, kann sie aufgrund dieser Methodik weiterhin auf das Framework zugreifen, wenn sie instanziiert wird.
Wirbel

@ Swivel Bitte helfen Sie Ich brauche Hilfe bei ähnlichen Problemen
TSR

12

Aufbauend auf der Antwort von @ Bergi , das Debug-Modul mit es6 zu verwenden, wäre dies die folgende

// 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

Ich glaube, Sie können es6-Modullader verwenden. http://babeljs.io/docs/learn-es6/

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

3
Aber wo landet das Ergebnis von m(youroptionshere)? Ich nehme an, Sie könnten schreiben System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... aber es ist nicht sehr klar.
Stijn de Witt

2
Wow, ich kann nicht glauben, dass es in E6 keinen eleganten Weg gibt, dies zu tun. So schreibe ich hauptsächlich Module.
Robert Moskal

3

Sie müssen nur diese 2 Zeilen hinzufügen.

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

1
Das bedeutet einfach, Parameter an eine Funktion zu übergeben, die Sie importiert haben und aufrufen. Es werden keine Optionen an das Modul übergeben, aus dem Sie es importieren . xModuleist hier irreführend. Was Sie tatsächlich haben, ist import func from 'module'; func('someOptions');.
Dan Dascalescu

1

Ich bin auf diesem Thread gelandet und habe nach etwas Ähnlichem gesucht und möchte zumindest für einige Fälle eine Art Lösung vorschlagen (siehe aber Bemerkung unten).

Anwendungsfall

Ich habe ein Modul, das unmittelbar nach dem Laden eine Instanziierungslogik ausführt. Ich mache nicht wie außerhalb des Moduls diese init Logik nennen (die die gleichen wie Anruf new SomeClass(p1, p2)oder new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })und gleichermaßen).

Ich mag es, dass diese Init-Logik einmal ausgeführt wird, eine Art singulärer Instanziierungsfluss, aber einmal in einem bestimmten parametrisierten Kontext.

Beispiel

service.js hat in seinem sehr grundlegenden Umfang:

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

Modul A macht:

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

Modul B macht:

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

So weit so gut: Der Service ist für beide Module verfügbar, wurde aber nur einmal initialisiert.

Problem

Wie kann man es als eine andere Instanz ausführen und sich erneut in einem anderen Kontext initiieren, beispielsweise in Modul C?

Lösung?

Ich denke darüber nach: Verwenden Sie Abfrageparameter. Im Service würden wir Folgendes hinzufügen:

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

Modul C würde tun:

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

Das Modul wird erneut importiert, die grundlegende Init-Logik wird ausgeführt und in der Konsole wird Folgendes angezeigt:

initialized in context special

Bemerkung: Ich würde mir raten, diesen Ansatz NICHT viel zu üben, sondern ihn als letzten Ausweg zu belassen. Warum? Mehr als einmal importiertes Modul ist eher eine Ausnahme als eine Regel, daher handelt es sich um ein etwas unerwartetes Verhalten, das als solches einen Verbraucher verwirren oder sogar seine eigenen "Singleton" -Paradigmen brechen kann, falls vorhanden.


0

Hier ist meine Sicht auf diese Frage am Beispiel des Debug-Moduls.

Auf der npm-Seite dieses Moduls haben Sie Folgendes:

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

In der obigen Zeile wird eine Zeichenfolge an das zu importierende Modul übergeben, um sie zu erstellen. So würden Sie dasselbe in ES6 tun


{debug as Debug} aus 'debug' importieren const debug = Debug ('http');


Hoffe das hilft jemandem da draußen.


Warum eine Antwort posten, die eine bereits gepostete dupliziert ?
Dan Dascalescu

1
Mein Fehler. Ich habe den genannten Beitrag nie gesehen. Ich habe mir nur die Frage angesehen und sie erstochen. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben.
Akinwale Folorunsho Habib

Bitte. Sie können die doppelte Antwort auch löschen, wenn Sie möchten.
Dan Dascalescu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.