ES6モジュールのインポートにオプションを渡す


144

ES6インポートにオプションを渡すことは可能ですか?

これをどのように翻訳しますか:

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

ES6に?


できるかわからない、モジュールローダーAPIがある、または少なくともある時点でのようなものを使用System.import(module)した、それが引数を許可するかどうかわからない、ES6についてもっと知っている人がおそらくそうするのでしょうか?
adeneo

このためのソリューションが提案されており、node.js(プラグイン経由)とwebpackにすでに実装があります。2ality.com/ 2017/01
Matt Browne

回答:


104

単一のimportステートメントでこれを行う方法はなく、呼び出しはできません。

したがって、直接呼び出すことはありませんが、基本的にはcommonjsがデフォルトのエクスポートで行うのと同じことを実行できます。

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

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

または、モナディックプロミスをサポートするモジュールローダーを使用すると、次のようなことができる場合があります。

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

新しいimportオペレーターでは、

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

または

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

ただし、おそらく動的インポートではなく静的インポートが必要です。


7
なんらかのimport x from 'module' use someoptions;構文のようなものがあったら良かったと思います
Fabrizio Giordano '28

1
@Fabrizio:さらに考えてみると、それほど役に立ちません。これは、モジュールが関数をエクスポートする場合にのみ機能し、imports(つまりimport {x, y} from 'module')という名前の場合は許可されないはずです。次に、複数の引数を渡したい場合、構文はどうすればよいですか?または、引数の配列を広げますか?これは狭いユースケースであり、基本的には関数呼び出しに別の構文を追加しようとしていますが、他のすべてのケースに対処できる関数呼び出しがすでにあります。
Felix Kling、2015

3
@FelixKling私はあなたに完全に同意します。私は古いExpress Webアプリを変換していましたvar session = require('express-session'); var RedisStore = require('connect-redis')(session);が、1行の解決策があるのか​​と思っていました。RedisStoreの割り当てを2行に分割することで、完全に生き残ることができます:)
Fabrizio Giordano

@FabrizioGiordano:import {default(someoptions) as x} from 'module'本当に必要な場合は、ES7のようなものを想像できます。
Bergi

2
以下のためにsession/ connect-redis例、私はこのような構文を想像されていますimport session from 'express-session'); import RedisStore(session) from 'connect-redis'
Jeff Handley 2015年

24

概念

これがES6を使用した私のソリューションです

@Bergiの応答と非常によく一致します。これは、class宣言に渡されるパラメーターを必要とするインポートを作成するときに使用する「テンプレート」です。これは、私が書いている同型フレームワークで使用されているため、ブラウザーとnode.jsでトランスパイラーで動作します(私はで使用Babelします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();

上記はfooコンソールに出力されます

編集

実世界の例

実際の例では、これを使用して、フレームワーク内の他のクラスやインスタンスにアクセスするための名前空間を渡します。単に関数を作成し、オブジェクトを引数として渡すため、次のようにクラス宣言で使用できます。

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

インポートはもう少し複雑でautomagical、私の場合、それが完全なフレームワークであることを考えると、本質的にこれが起こっています:

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

これが役に立てば幸いです!


インポートしたモジュールはすべてクラスなので、クラスをインスタンス化するときにパラメーターを渡してみませんか?
jasonszhao 2016年

1
@jasonszhaoここで注意すべき最も重要なことは、クラスMyViewがフレームワークの名前空間で使用可能な特定の項目を拡張することです。クラスにパラメーターとして単に渡すことは絶対に可能ですが、クラスがインスタンス化されるタイミングと場所にも依存します。移植性が影響を受けます。実際には、これらのクラスは、インスタンス化の方法が異なる他のフレームワーク(カスタムReactコンポーネントなど)に引き渡される場合があります。クラス自体がフレームワークのスコープ外にある場合、この方法論により、インスタンス化されたときにフレームワークへのアクセスを維持できます。
2016年

@Swivel私は同様の問題との助けを必要とする支援してください:stackoverflow.com/questions/55214957/...
TSR

12

es6 を使用してデバッグモジュールを使用するための@Bergi の答えを基にすると、次のようになります。

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

es6モジュールローダーを使用できると思います。 http://babeljs.io/docs/learn-es6/

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

3
しかし、結果はどこに行き着くのm(youroptionshere)でしょうか?私はあなたが書くことができると思いますSystem.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})...しかし、それはあまり明確ではありません。
Stijn de Witt

2
うわぁ、E6でこれを行うためのエレガントな方法がないとは信じられません。それが私が主にモジュールを書く方法です。
Robert Moskal

3

これらの2行を追加するだけです。

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

1
これは、インポートして呼び出している関数にパラメーターを渡すだけです。インポート元のモジュールにオプション渡していません。xModuleここでは誤解を招きます。あなたが実際に持っているのはimport func from 'module'; func('someOptions');です。
Dan Dascalescu

1

私はこのスレッドにたどり着き、いくらか類似したものを探しており、少なくともいくつかのケースでは、ある種の解決策を提案したいと思います(ただし、以下の備考を参照)。

使用事例

ロード時にすぐにインスタンス化ロジックを実行するモジュールがあります。モジュールの外でこのinitロジックを呼び出すの好きではありません(これは呼び出しnew SomeClass(p1, p2)などnew ((p1, p2) => class SomeClass { ... p1 ... p2 ... })と同じです)。

この初期化ロジックが1回だけ実行されるのが好きです。一種の特異なインスタンス化フローです、特定のパラメーター化されたコンテキストごとに1回実行されます。

service.js その非常に基本的なスコープで:

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

モジュールAは:

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

モジュールBは:

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

これまでのところ良好:サービスは両方のモジュールで使用できますが、初期化は1回だけです。

問題

別のインスタンスとして実行し、別のコンテキストでもう一度それを初期化する方法(モジュールCなど)

解決?

これは私が考えていることです:クエリパラメーターを使用します。このサービスには、次のものを追加します。

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

モジュールCは次のことを行います。

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

モジュールが再インポートされ、基本的なinitロジックが実行され、コンソールに表示されます。

initialized in context special

備考:私はこのアプローチをあまり実践しないことをお勧めしますが、最後の手段として残してください。どうして?複数回インポートされたモジュールはルールよりも例外的なものであるため、多少予期せぬ動作であり、コンシューマーを混乱させたり、もしあればそれ自体の「シングルトン」パラダイムを壊す可能性さえあります。


0

デバッグモジュールを例にして、この質問に対する私の見解を示します。

このモジュールのnpmページでは、次のようになります。

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

上記の行では、インポートするモジュールに文字列が渡され、構築されます。ES6で同じようにする方法は次のとおりです


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


これが誰かを助けることを願っています。


既に投稿された回答と重複する回答を投稿するのはなぜですか?
Dan Dascalescu

1
私の悪い。上記の投稿を見たことがない。ちょうど質問を見て、それに挑戦しました。お知らせいただきありがとうございます。
Akinwale Folorunsho Habib

どういたしまして。必要に応じて、重複する回答を削除することもできます。
Dan Dascalescu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.