21

我在我继承的一些代码上看到了一种模式。每个目录都有自己的 JS 文件,但也有一个 index.js,它实际上从另一个或多个 JS 文件导出项目。

我认为这样做是为了让您可以准确地看到要导出的内容,因为主要导出在 index.js 中,而主要代码在其他 js 文件中。

这个对吗?这种模式叫什么?

我应该继续使用这种模式吗?

4

5 回答 5

24

假设我有以下目录结构:

MyApp
├── app.js
├── test.js
├── package.json
├─┬ controllers
│ ├── index.js
│ ├── signIn.js
│ └── signOut.js
└─┬ views
  ├── index.js
  ├── signIn.js
  └── signOut.js

将以下代码放入index.js文件中...

// index.js
module.exports = {
  signIn: require('./signIn')
, signOut: require('./signOut')
};

...允许您访问require整个目录,例如...

// test.js
describe('controllers', () => {
  // ~/controllers/index.js
  const controllers = require('./controllers');

  it('performs a sign-in', () => {
    ...
  });
  it('performs a sign-out', () => {
    ...
  });
});

另一种方法是分别对require每个文件。

index.js不需要在目录中。您可能require在一个目录中没有一个文件index.js都一样。

// app.js
const signOut = require('./controllers/signOut.js')

但是,随着您的应用程序的增长,它会变得乏味。我使用一个包,require-directory因为在目录中键入每个文件也很乏味并且容易出错。

// index.js
module.exports = require('require-directory')(module);

/*

This yields the same result as:

module.exports = {
  signIn: require('./signIn')
, signOut: require('./signOut')
, ...
};

*/
于 2016-05-24T17:01:35.960 回答
13

ES6 CommonJS 模块语法

鉴于这两种常见的结构类型...

MyApp
│ // files divided per type (controllers, components, actions, ...)
├─┬ actions
│ ├── index.js
│ ├── signIn.js
│ └── signOut.js
├─┬ components ...
├─┬ reducers ...
├─┬ pages ...
│ 
│ // files divided per component
├─┬ components ...
│ ├── index.js 
│ ├── SimpleComponent.jsx
│ ├── AnotherComponent.duck.jsx // redux "duck" pattern
│ ├─┬ ComplexComponent // large complex logic, own actions, stylesheet, etc.
│ ...
├─┬ pages ...
│ ├── index.js 
│ ├─┬ App
│ │ ├── index.js // not necessary here, matter of habit
│ │ ├── App.jsx
│ │ ├── actions.js
│ │ └── reducer.js
│ └─┬ Dashboard
├── another.js
...

another.js您可以像这样简单地导入文件

import {signIn, signOut} from './actions'
import {App} from './pages'
import {ComplexComponent} from './components'

而不是这个(没有index.js文件)

import {signIn} from './actions/signIn'
import {signOut} from './actions/signOut'
import {App} from './pages/App/App' //notice the redundancy here
import {ComplexComponent} from './components/ComplexComponent/ComplexComponent'

更多阅读

ECMAScript 6 模块
导入 - JavaScript | MDN
Babel 转译器 - 现在为您的浏览器带来新的导入

构建 React 项目
React Redux “鸭子模式” - 组件的单文件方法

于 2017-10-27T13:21:52.490 回答
9

其他答案提供了很多很好的信息,但是要尝试专门回答您的问题“我应该继续使用这种模式”,我会说不,至少在大多数情况下。

问题是,这种模式需要额外的努力,因为您必须维护这些额外的index.js文件。根据我的经验,这种努力比简单地编写一个目录更长的import语句要大。另外,您可以index.js通过使用类似require-dir.

话虽如此,如果您正在创建一个将被大量人员使用的库,例如大型编程部门的关键模块或公共 NPM 模块,那么您的努力index.js变得更加合理。只要你有足够多的人使用你的模块,你的用户将(累积地)从你添加它们中节省更多的时间,而不是你失去维护它们的时间。

于 2018-01-21T02:21:26.263 回答
1

我将直接深入探讨您是否使用此模式的问题(因为其他答案不足以解决此问题)。

假设代码中的每个目录都代表一个独立模块(不依赖另一个模块工作)。使用这种模式将带来以下优势:

  1. 更好、更有组织的进口
  2. 每个模块的内部/外部定义之间的分离(类似于在接口/API 上使用私有/公共)

这样做的问题:

  1. 保持不同模块的松耦合可能非常烦人(JS/TS 不是纯 OOP)
  2. 需要对模块定义进行主动重构——更多的循环依赖。
  3. 将更多代码加载到内存中(即使未使用)——尽管我不确定这会有多糟糕,因为在捆绑生产代码时通常有一些优化可以解决这个问题。

循环依赖是非常有问题的,使用导入整个模块/目录index.js将导入其所有部分(在 中声明index.js)所以如果你有:

-- moduleA 
├-- comp1A // needs comp1B
├-- comp2A     
└-- index.js // export both comp1/2

-- moduleB
├-- comp1B 
├-- comp2B // needs comp2A
└-- index.js // export both comp1/2

示例案例 -comp1A需要来自的东西,comp1Bcomp2B需要来自的东西comp2A

导入特定文件(不带index.js- import something from './moduleB/comp1B')时,您不会有循环依赖。

但是如果你使用index.js( import something from './moduleB') 你会有循环依赖。

我的建议是index.js在正确的地方使用,并保持它们的维护!与小模块一起使用index.js将是完美的,但随着时间的推移它们会增长并且应该被分割。index.js在 common/shared/utils/misc/core (当你想放置在整个项目中使用的未分类和不相关的代码时,不管你怎么称呼它)模块使用是非常糟糕的。

于 2021-07-21T13:50:53.863 回答
0

那这个呢?

module.exports = {
  ...require('./moduleA'),
  ...require('./moduleB')
}

(moduleA.a 将被 moduleB.a 覆盖)

于 2021-05-16T08:38:44.760 回答