Joker karakter kullanarak bir dizindeki tüm dosyalardan modül içe aktarmak mümkün müdür?


256

ES6 ile, aşağıdaki gibi bir dosyadan birkaç dışa aktarım alabilirim:

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

Ancak, dosya başına bir modül bulundurmayı seviyorum. Sonunda böyle ithalatlar ile sonuçlanır:

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

Bunu yapabilmek isterim:

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

veya benzer bir şey, her dosyanın bir varsayılan dışa aktarma içerdiği ve her modülün dosyasıyla aynı şekilde adlandırıldığı anlaşılır.

Mümkün mü?


Bu mümkün. Lütfen babel babeljs.io/docs/learn-es2015 ... için modül belgelerine bakın "import {sum, pi}" lib / math ";" Kabul edilen cevap artık geçerli değil. Lütfen güncelleyin.
Eduard Jacko

6
@kresli Soruyu anladığınızı sanmıyorum. Dokümanlarda, lib/mathbirden çok dışa aktarma içeren bir dosyadır. Benim sorum, lib/math/her biri bir dışa aktarma içeren birkaç dosya içeren bir dizin.
Frambot

2
tamam anladım. Bu durumda Bergi doğrudur. Üzgünüz
Eduard Jacko

Yanıtlar:


231

Bunun mümkün olduğunu düşünmüyorum, ancak modül adlarının çözünürlüğü modül yükleyicilere kalmış, bu yüzden bunu destekleyen bir yükleyici uygulaması olabilir.

O zamana kadar lib/things/index.js, sadece aşağıdakileri içeren bir ara "modül dosyası" kullanabilirsiniz

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

ve yapmana izin verecek

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

6
Yardım için teşekkürler. Birlikte bu çalışma almak başardı index.jsbenzeyen: import ThingA from 'things/ThingA'; export {ThingA as ThingA}; import ThingB from 'things/ThingB'; export {ThingB as ThingB};. Diğer büyüler index.jskıpırdamazdı.
Frambot

2
Hm, export * fromçalışmalı. Denedin mi …from './ThingA'ya export ThingA from …? Hangi modül yükleyiciyi kullanıyorsunuz?
Bergi

7
Evet, her bir ThingA.js, ThingB.js, her biri adlandırılmış dışa aktarma yaptıysa orijinal yanıtınız işe yaradı. Açık.
Frambot

1
Dizin dosyasını belirtmeniz mi gerekiyor, yoksa yalnızca klasörü ve index.js'nin yükleneceğini belirtebilir misiniz?
Zorgatone

1
@Zorgatone: Bu, kullandığınız modül yükleyiciye bağlıdır, ancak evet genellikle klasör yolu yeterlidir.
Bergi

128

Yanıtta zaten verilen temadaki bir varyasyon, ancak buna ne dersiniz:

Bir Thing,

export default function ThingA () {}

İçinde things/index.js,

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

Sonra başka yerlerdeki her şeyi tüketmek için,

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

Veya sadece bazı şeyleri tüketmek için,

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

@ Wolfbiter'ın cevabına bir göz atmak ister misiniz? Parantezin neden işe yaramadığını iddia etmediğinden emin değilim.
Bergi

@Bergi Evet katılıyorum, wolfbiter'in geçerli ES6 olduğunu düşünmüyorum. Belki Babil'in eski bir versiyonunu veya başka bir transpiler kullanıyor?
Jed Richards

Bu nasıl aktarılıyor? Bir dizini içe aktarmak index.jsbenim için çözümlenmiyor . SystemJs + Babel kullanıyorum
jasonszhao

2
Sadece yazamaz export ThingA from './ThingA'yerineexport {default as ThingA} from './ThingA'
Petr PELLER

1
bu üç sarsıntıdan yararlanıyor mu? './things' öğesinden {ThingA} içe aktarırsam, pakete ThingB ve ThingC de eklenir mi?
Giorgio

75

Şu anki cevaplar bir çözüm önermektedir, ancak bunun neden var olmadığını bana bildirmiştir, bu yüzden bunu babelyapan bir eklenti oluşturdum .

Kullanarak yükleyin:

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

ardından .babelrcşununla ekleyin :

{
    "plugins": ["wildcard"]
}

ayrıntılı kurulum bilgileri için repoya bakınız


Bu, bunu yapmanızı sağlar:

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

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

yine, repo tam olarak ne yaptığı hakkında daha fazla bilgi içerir, ancak bu şekilde yapmak index.jsdosya oluşturmayı önler ve ayrıca readdirçalışma zamanında s yapmaktan kaçınmak için derleme zamanında gerçekleşir.

Ayrıca daha yeni bir sürümle tam olarak örneğiniz gibi yapabilirsiniz:

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

yukarıdakiyle aynı şekilde çalışır.


3
Uyarı, bu eklenti ile ilgili ciddi sorunlar yaşıyorum. Sorunlar muhtemelen dahili önbelleklemesinden kaynaklanır, kodunuz mükemmel olduğunda saçınızı çekeceksiniz, ancak dosya eklediğiniz ./lib/things;ve alınmadığı için komut dosyanız düzgün çalışmaz . Sebep olduğu sorunlar saçma. Ben sadece durum tanık, import *ekledi dosyayı almak için babel ile dosya değiştirirken, ama geri değiştirmek, değişiklik öncesi önbellek yeniden gibi, sorunu geri getiriyor. Dikkatle kullanın.
asukasz Zaroda

@ ŁukaszZaroda babel, ~/.babel.jsonbu garip davranışa neden olan dahili bir önbelleğe sahiptir . Ayrıca, bir izleyici veya sıcak yeniden yükleyici gibi kullanıyorsanız, yeni dosyayı kaydetmeniz gerekir, böylece yeni dizin listesiyle yeniden derlenir
Downgoat 23:17

@Downgoat Peki babel'in önbelleğini silmek dışında bunun üstesinden nasıl gelinir? Ve btw. Yorumunuzun doğru olduğunu düşünmüyorum. Babel'in önbelleğe almasını devre dışı bıraktım ve bu eklenti ile büyük sorunlar yaşadım. Kesinlikle tavsiye etmiyorum
SOReader

1
Btw başka sorunları olan herkese ekleyin, bpwc clear-cacheçünkü webpack ve diğer inşa süreçleri sessizce önbellekleyecektir
Downgoat

Bu harika bir fikir ama ben de işe yaramadı. Muhtemelen flowtyped kodumla bir çatışma, emin değilim, ama ithalatı nasıl yapılandırırsam yapayım `` ReferenceError: Foo tanımlı değil '' alıyordum.
jlewkovich

13

Büyük çirkin muglys! Bu olması gerekenden daha zordu.

Bir sabit varsayılanı dışa aktar

Bu kullanmak için harika bir fırsattır yayılmasını ( ...içinde { ...Matters, ...Contacts }aşağıda:

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

Ardından, komut satırından babil derlenmiş kodunu çalıştırmak için (proje kökünden /):

$ 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' }

Bir ağaç benzeri varsayılanı dışa aktarma

Mülklerin üzerine yazmamayı tercih ederseniz, şunları değiştirin:

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

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

Ve çıktı:

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

Birden fazla adlandırılmış dışa aktarmayı varsayılan olmadan dışa aktar

Eğer adanmış ediyorsanız DRY , ithalata sözdizimi de değişir:

// imports/collections/index.js

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

Bu, varsayılan dışa aktarma olmadan 2 adlandırılmış dışa aktarma oluşturur. Sonra değiştirin:

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

console.log(Matters, Contacts);

Ve çıktı:

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

Tüm adlandırılmış dışa aktarmaları içe aktar

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

Önceki örnekteki yıkıma dikkat edin 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' }

Uygulamada

Bu kaynak dosyalar göz önüne alındığında:

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

/myLib/index.jsTüm dosyaları paketlemek için a oluşturmak , alma / verme amacını bozar. İndex.js "sarmalayıcı dosyaları" aracılığıyla içe aktarma / dışa aktarma yoluyla her şeyi küresel hale getirmekten daha önce her şeyi küresel yapmak daha kolay olacaktır.

Belirli bir dosya istiyorsanız import thingA from './myLib/thingA';, kendi projelerinizde.

Modül için dışa aktarmalarla bir "sarma dosyası" oluşturmak yalnızca npm için paketleme yapıyorsanız veya çok yıllı çok ekipli bir projede mantıklıdır.

Şimdiye kadar mı yaptınız? Daha fazla ayrıntı için dokümanlara bakın.

Ayrıca Stackoverflow için yay nihayet kod çit biçimlendirme olarak üç `ü destekliyor.


10

Zaman uyumsuz import () kullanabilirsiniz:

import fs = require('fs');

ve sonra:

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

2
Dinamik ithalat böyle güzel. Soru sorulduğunda kesinlikle yoktu. Cevap için teşekkürler.
Frambot

6

Kabul edilen soruya benzer, ancak her oluşturduğunuzda dizin dosyasına yeni bir modül eklemenize gerek kalmadan ölçeklendirmenize olanak tanır:

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

Bir takma ad olarak içe ./example.js
aktarmaya

benim için çalışmıyor (webpack 4.41, babel 7.7)
Edwin Joassart

3

Onları birkaç kez kullandım (özellikle verileri birçok dosyaya bölen büyük nesneler oluşturmak için (örn. AST düğümleri)), bunları oluşturmak için küçük bir komut dosyası hazırladım (ki bu yüzden herkes kullanabilirsiniz).

Kullanım (şu anda dışa aktarma dosyasını kullanmak için babel kullanmanız gerekir):

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

Aşağıdakileri içeren bir dosya oluşturur:

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

Sonra sadece dosyayı tüketebilirsiniz:

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

, Pencerelerde düzgün çalışmıyor bir windows yolu (aynı yolu oluşturur \` instead of / ) also as an improvment you may want to allow two options like --filename` && --dest. Oluşturulan dosya saklanabilir ve wich adı altında olmalıdır özelleştirme izin Ayrıca yapar içeren dosya isimleri ile değil iş .(gibi user.model.js)
Yuri Scarbaci

2

@ Bergi'nin cevabına başka bir yaklaşım

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

export default {
 ThingA,
 ThingB,
 ThingC
}

Kullanımları

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

Çalışmaz. Ben sadece bir tepki app denedim ve geri döndü export '...' was not found in '.....
Hamid Mayeli

1

Gereksinimi de kullanabilirsiniz:

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

Ardından moduleHolder'ınızı dinamik olarak yüklenen denetleyicilerle kullanın:

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

0

Bu tam olarak istediğin şey değil, ama bu yöntemle componentsListdiğer dosyalarımda düşünce yineleyebilir ve componentsList.map(...)oldukça yararlı bulduğum gibi işlevi kullanabilirim !

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 kullanıyorsanız. Bu, dosyaları otomatik olarak içe aktarır ve api ad alanı olarak dışa aktarır .

Bu yüzden her dosya ekinde güncelleme yapmanıza gerek yok.

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;

Daktilo kullanıcıları için;

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

Kullanıcı atilkan'ın yaklaşımından alıp biraz değiştirebildim:

Daktilo kullanıcıları için;

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'de varsayılan olarak dışa aktarmazsanız, yalnızca {} dışa aktarırsanız, bunu yapmak mümkündür

// 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
Bu geçerli bir javascript değildir (tırnak işaretleri yoktur ./thing) ve olsa bile işe yaramaz. (Denedim ve işe yaramadı.)
John
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.