I just started a new React project and decided to use this pattern, which basically groups files according to their respective component:
├── actions
│ ├── LaneActions.js
│ └── NoteActions.js
├── components
│ ├── App
│ │ ├── App.jsx
│ │ ├── app.css
│ │ ├── app_test.jsx
│ │ └── index.js
│ ├── Editable
│ │ ├── Editable.jsx
│ │ ├── editable.css
│ │ ├── editable_test.jsx
│ │ └── index.js
...
│ └── index.js
├── constants
│ └── itemTypes.js
├── index.jsx
├── libs
│ ├── alt.js
│ ├── persist.js
│ └── storage.js
├── main.css
└── stores
├── LaneStore.js
└── NoteStore.js
What's confusing me is how index.js works in this case. As quoted:
The index.js files are there to provide easy entry points for
components. Even though they add noise, they simplify imports.
What the article doesn't do is go in depth of what's inside these files. In the case of the Editable component, what would Editable.jsx and index.js ideally look like?
This exact structure suggests that, for example, the Editable component would have everything about that component inside Editable.jsx. and I mean that your component code stays inside that file.
Now what's index for ? Inside index you would simply do something like this:
import Editable from './Editable.jsx';
export default Editable;
and that's it. This is helpful because inside other components or containers you can do this:
import Editable from '../Editable';
because it tries to access the index.js file by default thus not requiring any more info from you. It would import automatically the index.js file which imports the actual component itself. If you did not have an index.js file you would have had to do this:
import Editable from '../Editable/Editable';
which is kind of awkward. I don't like to have an index file that all it does is import a component and export it. What I usually do is just have all my component code inside the index.js file without the need of the Editable.jsx at all. That's up to you so feel free to take the approach you like better.
If one is using this directory per component pattern looking for a clean way to organize and access your modules, then the example above with a default export won't work with multiple files, e.g; this structure with a reducer directory:
── reducers
│ ├── todoReducer.js
│ └── filterReducer.js
│ └── themeReducer.js
│ └── index.js
├── components
├── App.js
├── app.css
└── index.js
So reducers/index.js would look something like this:
// index.js
import filterReducer from './filterReducer';
import todoReducer from './todoReducer';
import theme from './themeReducer';
export { filterReducer, todoReducer, theme };
...whether originally exported as default or named files in their original files, they are named exports now, and can be used cleanly in App.js as follows:
// App.js
import { filterReducer, todoReducer, theme } from '../reducers';
So we can avoid all this noise:
import filterReducer from './reducers/filterReducer';
import todoReducer from './reducers/todoReducer';
import theme from './reducers/theme';
You can also leverage it for module namespaces, e.g.
//MyNamespace/index.js
import Mod1 from './Mod1' //assumes ./Mod1.js
import Mod2 from './Mod2' //assumes ./Mod2.js
export{
Mod1,
Mod2
}
Then in other files you can import with a namespace:
//SomeOtherFile.js
import * as NamespaceToUse from './MyNamespace'
// Then access as:
NamespaceToUse.Mod1
NamespaceToUse.Mod2
There is no real benefit to using indexes for a front-end web application (whether written in React or not). If anything they are detrimental to optimal work on such project.
Organising imports should be automated and developer should not be concerned with it at all. Importing needed modules (component or not) can be automated by IDE suggestion (Intellij, WebStorm, VSC, all have those features), all you need to do is to start typing a Component's name.
Organising and optimising import structure can be done automatically on save via tools like prettier-plugin-organize-imports. There really is no need to manually interfere with imports, unless you have an import conflict.
Given that applications tend to grow, and future component folder structure is not deterministic, upkeeping of index files(dead weight) is an unnecessary overhead. Also most IDE's will open the index file instead intended Component if you ctrl/CMD click on a Component name, which is rather annoying and just distracts from you getting where you need to be (and if you need to write a lot of code, and need to look into dozens of components every minute, will become a real pain real fast).
Where indexes may be useful is, when you're writing a modular library (not an app), and you'd like to organise imports for the actual users of your library. You then also have the need of separating internal code from public/documented code. Libraries tend to have a more rigid structure, with clearer top level modules, which follow a specific segregation, which makes indexes less likely to be edited unless a new public/documented functionality needs to be exposed or deprecated. In this case indexes are useful, since they effectively create the interface for your library.
Based on the above indexes do not have a useful purpose in web applications source, but unfortunately they seem to be fashionable in some projects.
We currently have a component index file like this
/components/index.js
export { AutoCompleteInput } from './AutoCompleteInput';
export { AutoScrollWidgetRepositioning } from './AutoScrollWidgetRepositioning';
export { BrowserMessages } from './BrowserMessages';
export { CheckboxInput } from './CheckboxInput';
And a component index file like this
/components/AutcompleteInput/index.js
/* eslint-disable import/prefer-default-export */
export { default as AutoCompleteInput } from './AutoCompleteInput';
This means we can import components like this into other components.
/componnts/Form/Form.jsx
import {
AutoScrollWidgetRepositioning,
BrowserMessages,
HeadSection,
InitialWidgetLoadEventManager,
PageLayout,
} from '..';
This makes the import tree clean and tidy, however the downside of this, which i am currently finding out is that there are dependency cycle errors i.e. the import is importing itself, thus an issue. I am coming to the conclusion that index files may better be the actual component so the imports are not import { CheckboxInput } from './CheckboxInput/CheckboxInput' and stay as
import { CheckboxInput } from './CheckboxInput'.
TLDR: index files prevent an echo, but don't over use them else you may come across a cyclical import issue.
Related
This seems like a dumb question, but I struggle to find the answer.
The situation
Here is my folder structure:
myProject/
├── module1/
│ ├── config.ts
│ └── init.ts #symlink
├── module2/
│ ├── config.ts
│ └── init.ts #symlink
└── symlinks/
└── init.ts # the real not duplicated file
The file init.js import local files like so:
import config from './config'
// ...
The problem
The problem is that typescript throws Cannot find module './config' or its corresponding type declarations
I tried playing with typescript option preserveSymlinks but it didn't solve my problem
I know about other ways to achieve my goal but it's overkill for just one file and it doesn't solve relaying on a relative path (like creating a npm module, creating a function and pass relative file content as parameter or even generating files at runtime...)
=> I am working with typescript in a monorepo.
Is it possible to use symlinks this way? If no, are there other (simple) alternatives?
I am not sure where to find info about folder/file naming conventions so, I'm going to post it here, hoping this question will make sense. In my previous job I came across two component naming options (used for building components / sub-components / etc in a React project).
Options:
Option A:
.
├── components/
│ └── SubComponent/
│ ├── SubComponent.js → // export default function SubComponent(){ return <></> }
│ └── index.js → // export { default } from './SubComponent'
└── App.js → // import SubComponent from './components/SubComponent'
Option B:
.
├── components/
│ └── RandomSubFolder/
│ └── ComponentName.js → // export default function ComponentName(){ return <></> }
└── App.js // import ComponentName from './components/RandomSubFolder/ComponentName'
To Sum Up:
In both cases we are talking about a large number of components, sub-components, sub-sub-components and so on.
I know index.js ( which allows a simple import based on its parent foldername ) adds noise but is it the case that Option A is preferred for its simplicity despite this or Option B ( which relies of filename )?
Would like to be able to import any component in the components directory, directly from the components directory.
The current directory structure is:
src
├── components
│ ├── Camera.tsx
│ ├── Keyboard.tsx
│ └── index.ts
└── screens
└── App.tsx
And would like to be able to import as follows:
// src/screens/App.tsx
import { Keyboard } from '../components'
The first option is obviously to maintain a long list of exports in src/components/index.ts:
// src/components/index.ts
export { Camera } from './Camera'
export { Keyboard } from './Keyboard'
However, this is cumbersome to maintain. Is there a way using glob and the export object to automagically export all components, or possibly another way all together?
Since you are using TypeScript, why not just use the paths in TsConfig like described here?
You could achieve that by editing your index.ts to be like this
src
├── components
│ ├── Camera.tsx
│ ├── Keyboard.tsx
│ └── index.ts <=== this file
└── screens
└── App.tsx
export * from './Camera'
export * from './Keyboard'
In this case, you need to create an index.ts file in your components directory.
First, import all of your components in it:
import Camera from './Camera'
import Keyboard from './Keyboard'
// and so on for other components
Now, export all of them:
import Camera from './Camera'
import Keyboard from './Keyboard'
export Camera;
export Keyboard;
This can be simplified in this way:
export Camera from './Camera'
export Keyboard from './Keyboard'
Finally, use the './components' path to import the Camera and other components as well:
import { Keyboard, Camera } from '../components'
Note 1: Using this type of imports/exports will cause problems with code splitting or using Suspense/Lazy methods.
Note 2: debugging will be harder with a general index file.
I am currently trying to build my first webapp using vue.js
Now 2 days of tutorials deep I am still not 100% sure how to structure a basic application.
Using the vue-cli and webpack already makes a nice structure, including a /src Folder with components and a /router Folder for routing.
Now my plan is to create a ToDo App. I want to dynamically switch between [show todos] and [add todo], which is just a form with a submit button.
I have already achieved it by using it without components and the cli.
My structure would be:
App.vue -> buttons with the two router-link to components/ShowTodos.vue & components/AddTodos.vue
components/ShowTodos.vue -> Table including the todo list
components/AddTodos.vue -> Form with submit button
Now the routing part works, I am able to switch between those two components.
Now 2 Questions:
How can I push the information from the form in the AddTodos component into an Array in the ShowTodos component in order to loop through there ?
Is this a proper way to structure an vue app, and if not how can I improve it ?
Thank you very much.
This is the first time for me using a component based JS Framework, so its pretty hard to follow along.
On structuring your vuejs application , this can be helpful
app/
moduleA/
components/
index.js
routes.js
moduleB/
components/
index.js
routes.js
index.js
routers.js
main.vue
router/
components/ -> shared
main.js
// app/routes.js
import { routes as moduleA } from './moduleA'
import { routes as moduleB } from './moduleB'
export default [ ...moduleA, ...moduleB ]
// app/moduleA/index.js
export { default as routes } from './routes'
// app/moduleB/index.js
export { default as routes } from './routes'
// app/index.js
export { default as routes } from './routes
'
About the second question, I did some researches, and that's what I recommend:
.
├── app.css
├── App.vue
├── assets
│ └── ...
├── components
│ └── ...
├── main.js
├── mixins
│ └── ...
├── router
│ └── index.js
├── store
│ ├── index.js
│ ├── modules
│ │ └── ...
│ └── mutation-types.js
├── translations
│ └── index.js
├── utils
│ └── ...
└── views
└── ...
Read more here: https://medium.com/#sandoche/how-to-structure-a-vue-js-project-eabe75161882
I can recommend this boilerplate. It has a very good structure and I am now using it in every project.
/components
/layouts
/mixins
/pages
/routes
/services
/store
/transformers
He also explains the structure very well. https://github.com/petervmeijgaard/vue-2.0-boilerplate#structure
I am seeing a pattern on some code I have inherited. Each directory has its JS file but there is also a index.js that actually exports items from the other JS file or files.
I presume this is done so you can see exactly what you are exporting, as the main exports are in index.js and the main code is in the other js file or files.
Is this correct? What is this pattern called ?
Should I continue using this pattern.
Let's say I have the following directory structure:
MyApp
├── app.js
├── test.js
├── package.json
├─┬ controllers
│ ├── index.js
│ ├── signIn.js
│ └── signOut.js
└─┬ views
├── index.js
├── signIn.js
└── signOut.js
Placing the following code inside the index.js files...
// index.js
module.exports = {
signIn: require('./signIn')
, signOut: require('./signOut')
};
...allows you to require an entire directory like...
// test.js
describe('controllers', () => {
// ~/controllers/index.js
const controllers = require('./controllers');
it('performs a sign-in', () => {
...
});
it('performs a sign-out', () => {
...
});
});
The alternative is to require each file individually.
Having an index.js in a directory is not required. You may require a file in a directory without an index.js all the same.
// app.js
const signOut = require('./controllers/signOut.js')
However, it gets tedious as your app grows. I use a package like require-directory as typing out each file in a directory is also tedious and somewhat error prone.
// index.js
module.exports = require('require-directory')(module);
/*
This yields the same result as:
module.exports = {
signIn: require('./signIn')
, signOut: require('./signOut')
, ...
};
*/
ES6 CommonJS Module syntax
Given these two common types of structures...
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
...
You can simply import files in another.js like this
import {signIn, signOut} from './actions'
import {App} from './pages'
import {ComplexComponent} from './components'
instead of this (without index.js files)
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'
More reading
ECMAScript 6 modules
import - JavaScript | MDN
Babel transpiler - brings the new imports to your browser now
Structuring React projects
React Redux "Ducks pattern" - a single file approach for components
The other answers provide a lot of great information, but to try and specifically answer your question 'Should I continue using this pattern", I'd say no, at least most of the time.
The thing is, this pattern requires extra effort, as you have to maintain those extra index.js files. In my experience that effort is greater than the effort to simply write one-directory-longer import statements. Plus, you can get the same functionality you'd get from having an index.js without one, by using a module like require-dir.
All that being said, if you are making a library that will be consumed by a large number of people, like a critical module in a large programming department, or a public NPM module, then the effort of an index.js becomes more justified. As long as you have enough people using your modules, your users will (cumulatively) save more time from you adding them than you will lose maintaining them.
I will directly dive into your question on whether to use this pattern or not (as other answers are not sufficient for this).
Assuming that each directory in your code represents a standalone module (doesn't rely on another module to work). Using this pattern will give these advantages:
Better and more organized imports
Separation between internal/external definitions of each module (similar to using private/public on an interface/API)
The problems with this:
It can be very tiresome to keep loose-coupling of the different modules (JS/TS is not pure OOP)
Requires active refactoring to modules definition - more circular dependencies.
Loads more code to memory (even if unused) - though I'm not sure how bad this can be as there are optimizations that usually fix this problem when bundling production code.
Circular dependencies are very problematic, importing the whole module/directory using index.js will import all of its parts (that are declared in index.js) so if you have:
-- moduleA
├-- comp1A // needs comp1B
├-- comp2A
└-- index.js // export both comp1/2
-- moduleB
├-- comp1B
├-- comp2B // needs comp2A
└-- index.js // export both comp1/2
Example case - comp1A needs something from comp1B while comp2B needs something from comp2A
When importing the specific files (without index.js - import something from './moduleB/comp1B') you won't have circular dependencies.
But if you use index.js (import something from './moduleB') you will have circular dependencies.
My recommendation is to use index.js in the right places, and to keep those maintained! Using index.js with small modules will be perfect, but with time they will grow and should be divided. index.js is very bad to use in common/shared/utils/misc/core (whatever you call it when you want to put uncategorized and unrelated code that is used across your whole project) module.
What about this?
module.exports = {
...require('./moduleA'),
...require('./moduleB')
}
(moduleA.a will be overridden by moduleB.a)