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


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.