Przekaż opcje do importu modułu ES6

144

Czy można przekazać opcje do importu ES6?

Jak to tłumaczysz:

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

do ES6?

Fabrizio Giordano
źródło
Nie jestem pewien, czy możesz, istnieje interfejs API modułu ładującego, a przynajmniej był kiedyś, który używał czegoś takiego System.import(module), nie jestem pewien, czy to zezwala na argumenty, czy nie, prawdopodobnie ktoś, kto wie więcej o ES6, robi?
adeneo
Jest na to proponowane rozwiązanie, dla którego istnieją już implementacje w node.js (poprzez wtyczkę) i webpack
Matt Browne

Odpowiedzi:

104

Nie ma sposobu, aby to zrobić za pomocą jednej importinstrukcji, nie pozwala na wywołania.

Więc nie nazwałbyś tego bezpośrednio, ale zasadniczo możesz zrobić to samo, co commonjs robi z domyślnymi eksportami:

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

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

Alternatywnie, jeśli używasz modułu ładującego, który obsługuje monadyczne obietnice, możesz być w stanie zrobić coś takiego

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

Z nowym importoperatorem może się to stać

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

lub

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

jednak prawdopodobnie nie chcesz dynamicznego importu, ale statyczny.

Bergi
źródło
7
Dziękuję. Chciałbym, żeby było coś w rodzaju import x from 'module' use someoptions;składni
Fabrizio Giordano
1
@Fabrizio: Jeśli się nad tym zastanowić, nie byłoby to tak pomocne. Działałoby to tylko wtedy, gdy moduł eksportuje funkcję i prawdopodobnie nie powinno być dozwolone, gdybyśmy nazwali Import (tj import {x, y} from 'module'.). Jaka powinna być składnia, jeśli chcę przekazać wiele argumentów? Albo rozłożyć szereg argumentów? Jest to wąski przypadek użycia i zasadniczo próbujesz dodać inną składnię do wywołania funkcji, ale mamy już wywołania funkcji, które pozwalają nam zająć się wszystkimi innymi przypadkami.
Felix Kling
3
@FelixKling Całkowicie się z tobą zgadzam. Konwertowałem starą aplikację ekspresową i napotkałem, var session = require('express-session'); var RedisStore = require('connect-redis')(session);że po prostu zastanawiałem się, czy istnieje rozwiązanie jednokreskowe. Całkowicie przeżyję, dzieląc przydział RedisStore na 2 linie :)
Fabrizio Giordano
@FabrizioGiordano: Mogę sobie wyobrazić coś takiego jak import {default(someoptions) as x} from 'module'w ES7, jeśli naprawdę jest taka potrzeba.
Bergi
2
Dla session/ connect-redisprzykład I zostały wyobrażając składnię tak: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Jeff Handley
24

Pojęcie

Oto moje rozwiązanie przy użyciu ES6

Bardzo dobrze wpisuje się w odpowiedź @ Bergi, jest to „szablon”, którego używam podczas tworzenia importu, który wymaga przekazania parametrów class deklaracji. Jest to używane w izomorficznym frameworku, który piszę, więc będzie działać z transpilerem w przeglądarce i node.js (używam Babelz 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();

Powyższe zostanie wyświetlone foow konsoli

EDYTOWAĆ

Przykład z prawdziwego świata

W przypadku rzeczywistego przykładu używam tego do przekazywania przestrzeni nazw w celu uzyskania dostępu do innych klas i instancji w ramach. Ponieważ po prostu tworzymy funkcję i przekazujemy obiekt jako argument, możemy go użyć z naszą deklaracją klasy taką jak:

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

Import jest nieco bardziej skomplikowany iw automagicalmoim przypadku jest to cały framework, ale zasadniczo dzieje się tak:

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

Mam nadzieję, że to pomoże!

Obracać
źródło
Ponieważ wszystkie zaimportowane moduły są klasami, dlaczego nie przekazać parametru podczas tworzenia wystąpienia klasy?
jasonszhao
1
@jasonszhao Najważniejszą rzeczą do zapamiętania jest to, że klasa MyViewrozszerza niektóre elementy dostępne w przestrzeni nazw frameworka. Chociaż jest absolutnie możliwe, aby po prostu przekazać go jako parametr do klasy, zależy to również od tego, kiedy i gdzie tworzona jest instancja klasy; ma to wpływ na przenośność. W praktyce te klasy mogą zostać przekazane innym frameworkom, które mogą tworzyć ich instancje w inny sposób (np. Niestandardowe komponenty React). Gdy klasa znajdzie się poza zakresem struktury, może nadal zachować dostęp do struktury po jej wystąpieniu z powodu tej metodologii.
Obrót
@Swivel Proszę o pomoc Potrzebuję pomocy z podobnym problemem: stackoverflow.com/questions/55214957/ ...
TSR
12

Opierając się na @ BERGI za odpowiedź używać moduł debugowania za pomocą ES6 byłby następujący

// 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!');
mummybot
źródło
4

Uważam, że można użyć modułów ładujących es6. http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});
user895715
źródło
3
Ale gdzie m(youroptionshere)kończy się wynik? Przypuszczam, że mógłbyś napisać System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... ale to nie jest zbyt jasne.
Stijn de Witt
2
Wow, nie mogę uwierzyć, że nie ma eleganckiego sposobu na zrobienie tego w E6. Tak właśnie piszę głównie moduły.
Robert Moskal
3

Musisz tylko dodać te 2 linie.

import xModule from 'module';
const x = xModule('someOptions');
Mansi Teharia
źródło
1
To po prostu przekazanie parametrów do funkcji, którą zaimportowałeś i którą wywołujesz. Nie przekazuje żadnych opcji do modułu, z którego go importujesz . xModulewprowadza w błąd. To, co tak naprawdę masz, to import func from 'module'; func('someOptions');.
Dan Dascalescu
1

Wylądowałem w tym wątku, szukając czegoś podobnego i chciałbym zaproponować rodzaj rozwiązania, przynajmniej w niektórych przypadkach (ale zobacz uwagę poniżej).

Przypadek użycia

Mam moduł, który uruchamia logikę instancji natychmiast po załadowaniu. Ja nie jak nazwać tę startowy logikę zewnątrz modułu (który jest taki sam jak zaproszenia new SomeClass(p1, p2)lubnew ((p1, p2) => class SomeClass { ... p1 ... p2 ... }) i podobne).

Podoba mi się, że ta logika init uruchomi się raz, rodzaj pojedynczego przepływu instancji, ale raz dla określonego sparametryzowanego kontekstu.

Przykład

service.js ma w swoim podstawowym zakresie:

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

Moduł A robi:

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

Moduł B robi:

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

Jak dotąd dobrze: usługa jest dostępna dla obu modułów, ale została zainicjowana tylko raz.

Problem

Jak sprawić, by działał jako kolejna instancja i ponownie zainicjował się w innym kontekście, na przykład w module C?

Rozwiązanie?

Właśnie o tym myślę: użyj parametrów zapytania. W usłudze dodalibyśmy:

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

Moduł C zrobiłby:

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

moduł zostanie ponownie zaimportowany, uruchomi się jego podstawowa logika init i zobaczymy w konsoli:

initialized in context special

Uwaga: sam radziłbym NIE ćwiczyć zbyt często tego podejścia, ale zostawić je w ostateczności. Czemu? Moduł zaimportowany więcej niż jeden raz jest raczej wyjątkiem niż regułą, więc jest to nieco nieoczekiwane zachowanie i jako takie może zmylić konsumentów lub nawet złamać własne paradygmaty „singleton”, jeśli takie istnieją.

GullerYA
źródło
0

Oto moje podejście do tego pytania na przykładzie modułu debugowania;

Na stronie npm tego modułu masz to:

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

W powyższej linii ciąg jest przekazywany do modułu, który jest importowany w celu skonstruowania. Oto jak zrobiłbyś to samo w ES6


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


Mam nadzieję, że to komuś pomoże.

Akinwale Folorunsho Habib
źródło
Po co publikować odpowiedź, która jest duplikatem już opublikowanej ?
Dan Dascalescu
1
Mój błąd. Nigdy nie widziałem wspomnianego postu. Po prostu spojrzał na pytanie i zadał mu pytanie. Dziękuję za powiadomienie mnie o tym.
Akinwale Folorunsho Habib
Nie ma za co. Jeśli chcesz, możesz też usunąć zduplikowaną odpowiedź.
Dan Dascalescu