簡體   English   中英

是否可以使用通配符從目錄中的所有文件導入模塊?

[英]Is it possible to import modules from all files in a directory, using a wildcard?

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

或類似的東西,根據理解的約定,每個文件包含一個默認導出,並且每個模塊的名稱與其文件相同。

這可能嗎?

我不認為這是可能的,但是 afaik 模塊名稱的解析取決於模塊加載器,因此可能有一個加載器實現支持這一點。

在那之前,你可以在lib/things/index.js中使用一個中間的“模塊文件”, lib/things/index.js包含

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

它可以讓你做

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

只是答案中已經提供的主題的一個變體,但是這個怎么樣:

在一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'

當前的答案提出了一種解決方法,但它讓我煩惱為什么它不存在,所以我創建了一個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/*';

與上述相同。

偉大的咕嚕咕嚕! 這比它需要的更難。

導出一個平面默認值

這是使用傳播... 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: '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

創建一個/myLib/index.js來捆綁所有文件違背了導入/導出的目的。 首先將所有內容設為全局性比通過 index.js“包裝文件”導入/導出使所有內容全局化要容易得多。

如果你想要一個特定的文件, import thingA from './myLib/thingA'; 在你自己的項目中。

僅當您為 npm 或多年多團隊項目打包時,為模塊創建帶有導出的“包裝文件”才有意義。

走到這一步了嗎? 有關更多詳細信息,請參閱文檔

另外,是的,Stackoverflow 終於支持三個`s 作為代碼圍欄標記。

您現在可以使用異步導入():

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

類似於已接受的問題,但它允許您在每次創建一個新模塊時無需向索引文件添加新模塊的情況下進行擴展:

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

我已經使用過它們幾次(特別是用於構建將數據拆分到多個文件(例如 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()

只是@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';

如果你正在使用 webpack。 這會自動導入文件並導出為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;

對於打字稿用戶;

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

您也可以使用 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)
  }

我能夠從用戶 atilkan 的方法中獲取並對其進行一些修改:

對於打字稿用戶;

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

}));

節點? 這樣做:

使用 index.js 創建一個文件夾,在 index 文件中,添加以下內容:

var GET = require('./GET');
var IS = require('./IS');
var PARSE = require('./PARSE');
module.exports = { ...GET, ...IS, ...PARSE};

並且,在文件 GET.js 或 IS.js 中正常導出:

module.exports = { /* something as you like */}

並且現在,您只需要包含 index.js ,例如:

const Helper = require('./YourFolder');

Helper將包含 YourFolder 中的所有功能。

再會!

這不完全是您所要求的,但是,通過這種方法,我可以在其他文件中遍歷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;

如果您不在 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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM