와일드 카드를 사용하여 디렉토리의 모든 파일에서 모듈을 가져올 수 있습니까?


256

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/*';

또는 각 파일에 하나의 기본 내보내기가 포함되어 있고 각 모듈의 이름이 파일과 동일하다는 이해 된 규칙을 사용하여 이와 유사한 것입니다.

이게 가능해?


이것은 가능하다. babel babeljs.io/docs/learn-es2015 모듈 설명서를 참조하십시오. "import / sum"에서 "import {sum, pi};" 허용 된 답변이 더 이상 유효하지 않습니다. 업데이트하십시오.
Eduard Jacko

6
@kresli 나는 당신이 그 질문을 이해하지 못한다고 생각합니다. 문서에는 lib/math여러 내보내기가 포함 된 파일이 있습니다. 내 질문에 lib/math/, 각각 하나의 내보내기를 포함하는 여러 파일이 들어있는 디렉토리입니다.
Frambot

2
알 겠어. 이 경우 Bergi가 맞습니다. 죄송합니다
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

2
흠, export * from작동합니다. 당신은 시도 …from './ThingA'또는 export ThingA from …? 어떤 모듈 로더를 사용하고 있습니까?
Bergi

7
예, 각 ThingA.js, ThingB.js가 각각 이름이 지정된 내보내기를 내 보낸 경우 원래 답변이 작동했습니다. 에 딱 맞다.
Frambot

1
인덱스 파일을 지정해야합니까 아니면 폴더 만 지정하면 index.js가 대신로드됩니까?
조르가 톤

1
@ Zorgatone : 사용중인 모듈 로더에 따라 다르지만 일반적으로 폴더 경로로 충분합니다.
Bergi

128

이미 답변에 제공된 주제의 변형이지만 어떻게됩니까?

A의 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

@Bergi 네, wolfbiter가 유효한 ES6이라고 생각하지 않습니다. 어쩌면 그는 이전 버전의 Babel 또는 다른 트랜스 필러를 사용하고 있습니까?
Jed Richards

이것이 어떻게 번역되고 있습니까? 디렉토리 가져 오기가 해결되지 않습니다 index.js. 내가 SystemJs + 바벨을 사용하고 있습니다
jasonszhao

2
export ThingA from './ThingA'대신 입력 할 수 없음export {default as ThingA} from './ThingA'
Petr Peller

1
이 세 가지 흔들림을 활용합니까? './things'에서 {ThingA}를 가져 오면 ThingB와 ThingC도 번들에 추가됩니까?
조르지오

75

현재 답변은 해결 방법을 제안하지만 이것이 존재하지 않는 이유를 알았습니다. 그래서 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있으며 런타임에 s 를 피하기 위해 컴파일 타임에 발생 합니다.

또한 최신 버전을 사용하면 예제와 똑같이 할 수 있습니다.

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

위와 동일하게 작동합니다.


3
경고,이 플러그인에 심각한 문제가 있습니다. 내부 캐싱에서 문제가 발생했을 수 있습니다. 코드가 완벽 할 때 머리카락을 빼낼 수는 있지만 파일을 추가했지만 가져 오지 않아 스크립트가 제대로 작동하지 ./lib/things;않습니다. 그것이 발생하는 문제는 말도 안됩니다. 방금 파일을 변경하여 import *babel이 추가 된 파일을 선택하도록하지만 상황을 목격하면 변경 전에 다시 캐시를 재사용하는 것처럼 문제를 다시 발생시킵니다. 주의해서 사용하십시오.
우 카슈 자로 다

@ ŁukaszZaroda babel은 ~/.babel.json이상한 행동을 일으키는 내부 캐시를 가지고 있습니다. 또한 감시자 또는 핫 리 로더처럼 사용하는 경우 새 파일을 저장해야 새 디렉토리 목록으로 다시 컴파일됩니다.
Downgoat

@ Downgoat 그래서 babel의 캐시 삭제를 제외하고 이것을 극복하는 방법은 무엇입니까? 그리고 btw. 귀하의 의견이 정확하지 않다고 생각합니다. babel의 캐싱을 비활성화했으며 해당 플러그인에 큰 문제가있었습니다. 완전히 권장하지 않음
SOReader

1
bpwc clear-cache웹팩 및 기타 빌드 프로세스가 여전히 자동으로 캐시되기 때문에 추가 문제가있는 사람에게는 Btw가 추가 됩니다.
Downgoat

이것은 좋은 생각이지만 작동시키지 못했습니다. 아마도 플로우 타입 코드와 충돌 할 수는 있지만 확실하지 않지만 가져 오기를 어떻게 구성했는지에 관계없이 ReferenceReference : Foo가 정의되지 않았습니다.
jlewkovich

13

큰 못 생겨요! 이것은 필요 이상으로 힘들었습니다.

플랫 기본값 하나 내보내기

이 사용할 수있는 좋은 기회가 확산 ( ...{ ...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' }

하나의 트리와 같은 기본값 내보내기

속성을 덮어 쓰지 않으려면 다음을 변경하십시오.

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

통지 destructuring 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을 지원합니다.


10

비동기 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

넣은 사람은 아니다 나도 (웹팩 4.41, 바벨 7.7) 작동
에드윈 Joassart

3

나는 그것들을 몇 번 사용했습니다 (특히 많은 파일 (예 : AST 노드)에 데이터를 분할하는 거대한 객체를 구축하는 데 사용). 그들을 구축하기 위해 작은 스크립트를 만들었습니다. 사용할 수 있습니다).

사용법 (현재 내보내기 파일을 사용하려면 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에서 제대로 작동하지 않음은 윈도우 경로 (같은 경로 생성 \` instead of / ) also as an improvment you may want to allow two options like --filename` && --dest. 생성 된 파일이 저장 및 느릅 나무의 이름으로해야합니다 사용자 정의를 허용도하지 포함하는 이름을 가진하지 작업 .(같은 user.model.js)
유리 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

당신은 또한 사용할 수 있습니다 :

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

웹팩을 사용하는 경우 파일을 자동으로 가져 와서 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
이것은 유효한 자바 스크립트가 아니며 (따옴표가 없습니다 ./thing), 존재하더라도 작동하지 않습니다. (내가 시도했지만 작동하지 않았다.)
John
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.