เป็นไปได้หรือไม่ที่จะนำเข้าโมดูลจากไฟล์ทั้งหมดในไดเรกทอรีโดยใช้ไวด์การ์ด?


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 ... guoted "import {sum, pi} จาก" lib / math ";" คำตอบที่ยอมรับไม่ถูกต้องอีกต่อไป โปรดอัปเดต
Eduard Jacko

6
@kresli ฉันไม่คิดว่าคุณเข้าใจคำถาม ในเอกสารlib/mathเป็นไฟล์ที่มีการส่งออกหลายรายการ ในคำถามของฉันlib/math/เป็นไดเรกทอรีที่มีหลายไฟล์แต่ละไฟล์มีการส่งออกหนึ่ง
Frambot

2
โอเคฉันเข้าใจแล้ว ในกรณีนั้น Bergi นั้นถูกต้อง ขออภัย
Eduard Jacko

คำตอบ:


231

ฉันไม่คิดว่ามันเป็นไปได้ แต่ afaik ความละเอียดของชื่อโมดูลขึ้นอยู่กับโมดูลตัวโหลดดังนั้นอาจมีการใช้ตัวโหลดเดอร์ที่สนับสนุนสิ่งนี้

ก่อนหน้านั้นคุณสามารถใช้ไฟล์โมดูล "ระดับกลาง" 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 เท่านั้นที่จะถูกโหลดแทน?
Zorgatone

1
@ Zorgatone: ขึ้นอยู่กับโหลดเดอร์โมดูลที่คุณใช้ แต่โดยปกติแล้วเส้นทางของโฟลเดอร์จะเพียงพอ
Bergi

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

@Bergi ใช่เห็นด้วยฉันไม่คิดว่า wolfbiter นั้นถูกต้อง ES6 บางทีเขาอาจใช้ Babel รุ่นเก่าหรือ transpiler อื่น ๆ
Jed Richards

สิ่งนี้เป็นวิธีการที่ transpiled? การนำเข้าไดเรกทอรีไม่ได้ช่วยแก้ปัญหาให้index.jsฉัน ฉันใช้ SystemJs + Babel
jasonszhao

2
คุณพิมพ์ไม่ได้export ThingA from './ThingA'แทนexport {default as ThingA} from './ThingA'
Petr Peller

1
สิ่งนี้ใช้ประโยชน์จากการเขย่าสามครั้งหรือไม่? ถ้าฉันนำเข้า {ThingA} จาก './things' จะเพิ่ม ThingB และ ThingC ในบันเดิลด้วยหรือไม่
Giorgio

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ที่รันไทม์

ด้วยรุ่นที่ใหม่กว่าคุณสามารถทำตามตัวอย่างของคุณได้:

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

ทำงานเหมือนข้างต้น


3
คำเตือนฉันมีปัญหารุนแรงกับปลั๊กอินนี้ ปัญหาอาจมาจากการแคชภายในคุณจะดึงผมออกมาเมื่อรหัสของคุณจะสมบูรณ์แบบ แต่สคริปต์ของคุณจะไม่ทำงานอย่างถูกต้องเพราะคุณเพิ่มไฟล์./lib/things;และไม่ได้หยิบขึ้นมา ปัญหาที่เกิดขึ้นนั้นไร้สาระ ฉันเพิ่งเห็นสถานการณ์เมื่อเปลี่ยนไฟล์ด้วยimport *ทำให้ babel รับไฟล์เพิ่ม แต่การเปลี่ยนกลับนำปัญหากลับมาเหมือนใช้แคชจากก่อนการเปลี่ยนแปลง ใช้ด้วยความระมัดระวัง
Łukasz Zaroda

@ ŁukaszZaroda babel มีแคชภายใน~/.babel.jsonซึ่งทำให้เกิดพฤติกรรมแปลก ๆ นี้ นอกจากนี้ถ้าคุณใช้งานเหมือน watcher หรือ hot reloader คุณต้องบันทึกไฟล์ใหม่ดังนั้นมันจะถูกคอมไพล์ด้วยรายชื่อได
เรคทอ

@Downgoat แล้วจะเอาชนะได้อย่างไรยกเว้นการลบแคชของ babel? และ btw ฉันไม่คิดว่าความคิดเห็นของคุณถูกต้อง ฉันแคชบาเบลปิดการใช้งานและมีปัญหาใหญ่กับปลั๊กอินนั้น ไม่แนะนำเลย
SOReader

1
Btw สำหรับทุกคนที่มีปัญหาเพิ่มเติมเพิ่มbpwc clear-cacheเพราะ webpack และกระบวนการสร้างอื่น ๆ จะยังคงแคชอย่างเงียบ ๆ
Downgoat

นี่เป็นความคิดที่ดี แต่ฉันก็ไม่สามารถทำให้มันใช้ได้ อาจเป็นความขัดแย้งกับรหัส flowtyped ของฉันฉันไม่แน่ใจ แต่ฉันได้รับ `ReferenceError: Foo ไม่ได้ถูกกำหนด 'ไม่ว่าฉันจะวางโครงสร้างการนำเข้าอย่างไร
jlewkovich

13

Great gugly muglys! มันยากกว่าที่คิด

ส่งออกค่าเริ่มต้นเดียว

นี่เป็นโอกาสที่ดีที่จะใช้การแพร่กระจาย ( ...ใน{ ...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);

สังเกตการทำลาย 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

การสร้าง a /myLib/index.jsเพื่อรวมไฟล์ทั้งหมดเป็นไปตามวัตถุประสงค์ของการนำเข้า / ส่งออก มันจะง่ายกว่าที่จะทำให้ทุกอย่างเป็นสากลในสถานที่แรกกว่าที่จะทำให้ทุกอย่างทั่วโลกผ่านการนำเข้า / ส่งออกผ่านทาง index.js "wrapper files"

หากคุณต้องการไฟล์เฉพาะimport thingA from './myLib/thingA';ในโครงการของคุณเอง

การสร้าง "ไฟล์แรปเปอร์" ที่มีการเอ็กซ์ปอร์ตสำหรับโมดูลนั้นสมเหตุสมผลถ้าคุณทำแพ็กเกจสำหรับ npm หรือในโปรเจ็กต์แบบหลายทีมหลายปี

ทำให้ไกลขนาดนี้ไหม? ดูเอกสารสำหรับรายละเอียดเพิ่มเติม

ยิ่งไปกว่านั้น yay สำหรับ Stackoverflow ในที่สุดก็รองรับมาร์กอัปรั้วรหัสสามรายการ


10

คุณสามารถใช้การนำเข้า async ():

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

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

มันจะไม่ทำงาน ฉันแค่พยายามมันใน app 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

หากคุณใช้ webpack สิ่งนี้จะนำเข้าไฟล์โดยอัตโนมัติและส่งออกเป็นapi namespace

ดังนั้นไม่จำเป็นต้องอัปเดตทุกครั้งที่เพิ่มไฟล์

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) และแม้ว่าจะเป็นเช่นนั้นก็จะไม่ทำงาน (ฉันลองแล้วก็ใช้ไม่ได้)
จอห์น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.