ワイルドカードを使用して、ディレクトリ内のすべてのファイルからモジュールをインポートすることは可能ですか?


256

ES6では、次のようにファイルからいくつかのエクスポートをインポートできます。

import {ThingA, ThingB, ThingC} from 'lib/things';

ただし、ファイルごとに1つのモジュールを持つ構成が好きです。私は次のようなインポートになります:

import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';

私はこれができるようになりたいです:

import {ThingA, ThingB, ThingC} from 'lib/things/*';

または同様のもの。各ファイルにはデフォルトのエクスポートが1つ含まれ、各モジュールにはそのファイルと同じ名前が付けられていることが理解されています。

これは可能ですか?


これは可能です。babel babeljs.io/docs/learn-es2015 ...「lib / math」からの「import {sum、pi}」を取得したモジュールのドキュメントを参照してください。受け入れられた回答はもはや有効ではありません。更新してください。
Eduard Jacko

6
@kresli私はあなたが質問を理解していないと思います。ドキュメントでlib/mathは、複数のエクスポートを含むファイルです。私の質問でlib/math/は、それぞれが1つのエクスポートを含む複数のファイルを含むディレクトリです。
Frambot 2015

2
なるほど、分かりました。その場合、ベルギは正しいです。申し訳ありません
Eduard Jacko

回答:


231

これは可能ではないと思いますが、モジュール名の解決はモジュールローダー次第なので、これをサポートするローダー実装があるかもしれません。

それまでは、以下をlib/things/index.js含むだけの中間的な「モジュールファイル」を使用できます。

export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';

そしてそれはあなたができるようになります

import {ThingA, ThingB, ThingC} from 'lib/things';

6
助けてくれてありがとう。私はこれindex.jsを次のように動作させることができました:import ThingA from 'things/ThingA'; export {ThingA as ThingA}; import ThingB from 'things/ThingB'; export {ThingB as ThingB};。の他の呪文はびくともしindex.jsないでしょう。
Frambot 2015

2
うーん、export * fromうまくいくはずです。試しました…from './ThingA'export ThingA from …?どのモジュールローダーを使用していますか?
Bergi

7
はい、元の答えは、ThingA.js、ThingB.js、それぞれが名前付きエクスポートをエクスポートした場合に機能しました。見つけて。
Frambot、2015

1
インデックスファイルを指定する必要がありますか、それともフォルダのみを指定して、代わりにindex.jsをロードできますか?
Zorgatone 2016年

1
@Zorgatone:使用しているモジュールローダーによって異なりますが、通常はフォルダーパスで十分です。
Bergi、2016年

128

答えですでに提供されているテーマのバリエーションですが、これはどうですか?

Thing

export default function ThingA () {}

things/index.js

export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'

次に、他のものをすべて消費するために、

import * as things from './things'
things.ThingA()

または、一部のみを消費するには、

import {ThingA,ThingB} from './things'

@wolfbiterの答えを見てみませんか?かっこが機能しないと主張する理由がわかりません。
ベルギ

@Bergiそうですね、wolfbiterは有効なES6ではないと思います。多分彼は古いバージョンのBabelを使用しているのでしょうか、それとも他のトランスパイラーを使用しているのでしょうか。
Jed Richards

これはどのように転移しているのですか?ディレクトリをインポートしても解決さindex.jsれません。私はSystemJs + Babelを使用しています
jasonszhao

2
export ThingA from './ThingA'代わりに単純に入力することはできませんexport {default as ThingA} from './ThingA'
Petr Peller

1
これは3つの揺れを利用していますか?'./things'から{ThingA}をインポートすると、ThingBとThingCもバンドルに追加されますか?
Giorgio

75

現在の回答は回避策を提案していますが、これが存在しない理由がわからないので、これを行うbabelプラグインを作成しました。

次を使用してインストールします。

npm i --save-dev babel-plugin-wildcard

それからあなたにそれを追加してください.babelrc

{
    "plugins": ["wildcard"]
}

詳細なインストール情報については、リポジトリを参照してください


これにより、次のことが可能になります。

import * as Things from './lib/things';

// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;

繰り返しになりますが、リポジトリには正確に何が行われるかについての詳細情報が含まれていますが、このようにindex.jsすると、ファイルの作成が回避され、コンパイルreaddir時に実行時にsが実行されるのを回避できます。

また、新しいバージョンでは、例とまったく同じように実行できます。

 import { ThingsA, ThingsB, ThingsC } from './lib/things/*';

上記と同じように機能します。


3
警告、このプラグインで深刻な問題が発生しています。問題はおそらく内部キャッシングに起因します。コードが完璧になると髪が抜けますが、ファイルを追加したため./lib/things;ピックアップされないため、スクリプトは正しく機能しません。それが引き起こす問題はばかげています。ファイルを変更するとimport *babelが追加されたファイルを取得するが、元に戻すと、変更前のキャッシュを再利用するなど、問題が発生するのを目の当たりにしました。注意して使用してください。
ルカシュZaroda

@ŁukaszZarodababelには、~/.babel.jsonこの奇妙な動作を引き起こす内部キャッシュがあります。また、ウォッチャーやホットリローダーなどを使用している場合は、新しいファイルを保存して、新しいディレクトリリストで再コンパイルする必要があります
Downgoat

@Downgoatでは、babelのキャッシュを削除することを除いて、これを克服するには そしてところで。あなたのコメントは正しいとは思いません。私はバベルのキャッシングを無効にしていて、そのプラグインでとても大きな問題がありました。まったくお勧めしません
SOReader 2017年

1
さらに問題が発生した場合は、追加しbpwc clear-cacheてください。webpackや他のビルドプロセスが引き続きサイレントキャッシュを行うためです
Downgoat

これは素晴らしいアイデアですが、うまく機能させることもできませんでした。フロータイプのコードとの競合の可能性がありますが、よくわかりませんが、インポートの構造に関係なく、「ReferenceError:Foo is not defined」と表示されていました。
jlewkovich

13

醜いマグライ!これは必要以上に困難でした。

フラットなデフォルトを1つエクスポートする

これは、使用する絶好の機会であるスプレッドを...{ ...Matters, ...Contacts }以下:

// imports/collections/Matters.js
export default {           // default export
  hello: 'World',
  something: 'important',
};
// imports/collections/Contacts.js
export default {           // default export
  hello: 'Moon',
  email: 'hello@example.com',
};
// imports/collections/index.js
import Matters from './Matters';      // import default export as var 'Matters'
import Contacts from './Contacts';

export default {  // default export
  ...Matters,     // spread Matters, overwriting previous properties
  ...Contacts,    // spread Contacts, overwriting previosu properties
};
// imports/test.js
import collections from './collections';  // import default export as 'collections'

console.log(collections);

次に、コマンドラインから(プロジェクトルート/から)babelコンパイル済みコード実行ます

$ npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node 
(trimmed)

$ npx babel-node --presets @babel/preset-env imports/test.js 
{ hello: 'Moon',
  something: 'important',
  email: 'hello@example.com' }

ツリーのようなデフォルトを1つエクスポートする

プロパティを上書きしたくない場合は、次のように変更します。

// imports/collections/index.js
import Matters from './Matters';     // import default as 'Matters'
import Contacts from './Contacts';

export default {   // export default
  Matters,
  Contacts,
};

そして出力は次のようになります:

$ npx babel-node --presets @babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
  Contacts: { hello: 'Moon', email: 'hello@example.com' } }

デフォルトなしで複数の名前付きエクスポートをエクスポートする

DRYに専念している場合、インポートの構文も変更されます。

// imports/collections/index.js

// export default as named export 'Matters'
export { default as Matters } from './Matters';  
export { default as Contacts } from './Contacts'; 

これにより、デフォルトのエクスポートなしで2つの名前付きエクスポートが作成されます。次に変更します。

// imports/test.js
import { Matters, Contacts } from './collections';

console.log(Matters, Contacts);

そして出力:

$ npx babel-node --presets @babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello@example.com' }

名前付きエクスポートをすべてインポートする

// imports/collections/index.js

// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
// imports/test.js

// Import all named exports as 'collections'
import * as collections from './collections';

console.log(collections);  // interesting output
console.log(collections.Matters, collections.Contacts);

前の例の分解 import { Matters, Contacts } from './collections';に注目してください。

$ npx babel-node --presets @babel/preset-env imports/test.js
{ Matters: [Getter], Contacts: [Getter] }
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello@example.com' }

実際には

これらのソースファイルを考えると:

/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js

/myLib/index.jsすべてのファイルをバンドルするを作成すると、インポート/エクスポートの目的が損なわれます。index.jsの「ラッパーファイル」を介してインポート/エクスポートを介してすべてをグローバルにするよりも、最初からすべてをグローバルにする方が簡単です。

import thingA from './myLib/thingA';自分のプロジェクトで特定のファイルが必要な場合。

モジュールのエクスポートで「ラッパーファイル」を作成することは、npmまたは複数年のマルチチームプロジェクトでパッケージ化している場合にのみ意味があります。

ここまで作った?詳細については、ドキュメントを参照してください。

また、Stackoverflowがコードフェンスマークアップとして3つの `sをサポートするようになりました。


10

async import()を使用できます:

import fs = require('fs');

その後:

fs.readdir('./someDir', (err, files) => {
 files.forEach(file => {
  const module = import('./' + file).then(m =>
    m.callSomeMethod();
  );
  // or const module = await import('file')
  });
});

2
動的インポートはそのようなものです。質問されたとき、彼らは確かに存在しませんでした。答えてくれてありがとう。
Frambot

6

受け入れられた質問に似ていますが、作成するたびに新しいファイルをインデックスファイルに追加する必要なしにスケーリングできます。

./modules/moduleA.js

export const example = 'example';
export const anotherExample = 'anotherExample';

./modules/index.js

// require all modules on the path and with the pattern defined
const req = require.context('./', true, /.js$/);

const modules = req.keys().map(req);

// export all modules
module.exports = modules;

./example.js

import { example, anotherExample } from './modules'

これは、エイリアスとしてインポートしようとすると機能しません./example.js
tsujp

どちらも機能しません(Webpack 4.41、Babel 7.7)
Edwin Joassart '30 / 12/30

3

私はそれらを数回使用しました(特に、多くのファイル(ASTノードなど)にデータを分割する大規模なオブジェクトを構築するため)、それらを構築するために小さなスクリプトを作成しました(npmに追加したので、他のすべての人それを使用できます)。

使用法(現在、エクスポートファイルを使用するにはbabelを使用する必要があります):

$ npm install -g folder-module
$ folder-module my-cool-module/

以下を含むファイルを生成します。

export {default as foo} from "./module/foo.js"
export {default as default} from "./module/default.js"
export {default as bar} from "./module/bar.js"
...etc

次に、ファイルを使用するだけです。

import * as myCoolModule from "my-cool-module.js"
myCoolModule.foo()

Windowsで正しく機能せず、Windowsパスとしてパスを生成します(\` instead of / ) also as an improvment you may want to allow two options like --filename` && --destは、作成されたファイルを保存する場所と名前をカスタマイズできるようにします。また、.(などuser.model.js)を含むファイル名では機能しません
Yuri Scarbaci

2

@Bergiの答えへのちょうど別のアプローチ

// lib/things/index.js
import ThingA from './ThingA';
import ThingB from './ThingB';
import ThingC from './ThingC';

export default {
 ThingA,
 ThingB,
 ThingC
}

用途

import {ThingA, ThingB, ThingC} from './lib/things';

動作しません。反応アプリで試してみたところ、戻りましたexport '...' was not found in '....
Hamid Mayeli

1

requireも使用できます:

const moduleHolder = []

function loadModules(path) {
  let stat = fs.lstatSync(path)
  if (stat.isDirectory()) {
    // we have a directory: do a tree walk
    const files = fs.readdirSync(path)
    let f,
      l = files.length
    for (var i = 0; i < l; i++) {
      f = pathModule.join(path, files[i])
      loadModules(f)
    }
  } else {
    // we have a file: load it
    var controller = require(path)
    moduleHolder.push(controller)
  }
}

次に、動的に読み込まれるコントローラーでmoduleHolderを使用します。

  loadModules(DIR) 
  for (const controller of moduleHolder) {
    controller(app, db)
  }

0

これは正確にはあなたが要求したものではありませんが、この方法をcomponentsList使用すると、他のファイルを繰り返し処理して、componentsList.map(...)かなり便利な関数を使用できます!

import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';
import StepFour from './StepFour';
import StepFive from './StepFive';
import StepSix from './StepSix';
import StepSeven from './StepSeven';
import StepEight from './StepEight';

const componentsList= () => [
  { component: StepOne(), key: 'step1' },
  { component: StepTwo(), key: 'step2' },
  { component: StepThree(), key: 'step3' },
  { component: StepFour(), key: 'step4' },
  { component: StepFive(), key: 'step5' },
  { component: StepSix(), key: 'step6' },
  { component: StepSeven(), key: 'step7' },
  { component: StepEight(), key: 'step8' }
];

export default componentsList;

0

webpackを使用している場合。これにより、ファイルが自動的にインポートされ、api名前空間としてエクスポートされます。

したがって、ファイルを追加するたびに更新する必要はありません。

import camelCase from "lodash-es";
const requireModule = require.context("./", false, /\.js$/); // 
const api = {};

requireModule.keys().forEach(fileName => {
  if (fileName === "./index.js") return;
  const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ""));
  api[moduleName] = {
    ...requireModule(fileName).default
  };
});

export default api;

Typescriptユーザーの場合。

import { camelCase } from "lodash-es"
const requireModule = require.context("./folderName", false, /\.ts$/)

interface LooseObject {
  [key: string]: any
}

const api: LooseObject = {}

requireModule.keys().forEach(fileName => {
  if (fileName === "./index.ts") return
  const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ""))
  api[moduleName] = {
    ...requireModule(fileName).default,
  }
})

export default api

0

ユーザーatilkanのアプローチを取り入れて、少し修正することができました。

Typescriptユーザーの場合。

require.context('@/folder/with/modules', false, /\.ts$/).keys().forEach((fileName => {
    import('@/folder/with/modules' + fileName).then((mod) => {
            (window as any)[fileName] = mod[fileName];
            const module = new (window as any)[fileName]();

            // use module
});

}));

-9

A、B、Cでデフォルトをエクスポートせず、{}だけをエクスポートする場合、それを行うことが可能です

// things/A.js
export function A() {}

// things/B.js
export function B() {}

// things/C.js
export function C() {}

// foo.js
import * as Foo from ./thing
Foo.A()
Foo.B()
Foo.C()

1
これは有効なjavascriptではありません(の前後に引用符はありません./thing)。たとえあったとしても機能しません。(試してみましたが、うまくいきませんでした。)
ジョン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.