Можно ли импортировать модули из всех файлов в каталоге, используя подстановочный знак?

С ES6 я могу импортировать несколько экспортов из файла, подобного этому:

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

Тем не менее, мне нравится организация одного модуля на файл. Я получаю импорт, как это:

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

Я не думаю, что это возможно, но afaik разрешает имена модулей до загрузчиков модулей, поэтому может быть реализована реализация загрузчика, которая поддерживает это.

До тех пор вы могли бы использовать промежуточный "файл модуля" в lib/things/index.js, который просто содержит

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

и это позволит вам делать

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

Ответ 2

Просто вариант на тему, уже представленную в ответе, но как насчет этого:

В 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'

Ответ 3

В текущих ответах предлагается обходное решение, но это меня раздражало, почему этого не существует, поэтому я создал плагин babel, который делает это.

Установите его, используя:

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

затем добавьте его в свой .babelrc с помощью:

{
    "plugins": ["wildcard"]
}

см. repo для подробной информации об установке


Это позволяет сделать это:

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

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

снова, repo содержит дополнительную информацию о том, что именно он делает, но при этом он избегает создания файлов index.js, а также происходит при время компиляции, чтобы избежать выполнения readdir во время выполнения.

Также с более новой версией вы можете сделать точно так же, как ваш пример:

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

работает так же, как и выше.

Ответ 4

Великие гугли магглы! Это было сложнее, чем нужно было.

Экспортировать одну квартиру по умолчанию

Это отличная возможность использовать распространение (... in {...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: '[email protected]',
};
// 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 из командной строки (из проекта root/):

$ 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: '[email protected]' }

Экспорт одного древовидного по умолчанию

Если вы не хотите перезаписывать свойства, измените:

// 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: '[email protected]' } }

Экспорт нескольких именованных экспортов без по умолчанию

Если вы посвящены 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: '[email protected]' }

Импортировать все именованные экспорты

// 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: '[email protected]' }

На практике

Учитывая эти исходные файлы:

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

Создание /myLib/index.js для /myLib/index.js всех файлов не /myLib/index.js выполнить импорт/экспорт. Во-первых, было бы проще сделать все глобальным, чем сделать все глобальным с помощью импорта/экспорта через index.js "файлы-оболочки".

Если вам нужен определенный файл, import thingA from './myLib/thingA'; в ваших собственных проектах.

Создание "файла-обертки" с экспортом для модуля имеет смысл только в том случае, если вы собираете пакет для npm или в многолетнем многопользовательском проекте.

Сделал это так далеко? Смотрите документы для более подробной информации.

Кроме того, yay для Stackoverflow наконец поддерживает три в качестве разметки кода.

Ответ 5

Я использовал их несколько раз (в частности, для создания массивных объектов, разделяющих данные по многим файлам (например, узлам AST)), для их создания я сделал крошечный script (который я только что добавил до 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()

Ответ 6

Просто другой подход к ответу @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';

Ответ 7

Вы можете использовать асинхронный импорт():

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')
  });
});

Ответ 8

Это не совсем то, о чем вы просили, но с помощью этого метода я могу перебирать все componentsList Component в других моих файлах и использовать такие функции, как 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;

Ответ 9

Вы также можете использовать 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)
  }

Ответ 10

Аналогичен принятому вопросу, но позволяет масштабировать без необходимости добавления нового модуля в индексный файл каждый раз, когда вы его создаете:

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

Ответ 11

если вы не экспортируете по умолчанию в 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()