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)
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 recently started my first project with Next.js and since then my pages directory has grown a lot. Now I want to separate my pages and group them into modules, ending up with something like 'src/modules/*/pages/*'.
Researching the topic I came accross exportPathMap, a function that I can include in my next.config.js file and then map custom paths to my pages, but it seems like I'd need to add a new path for every page I create, which is not ideal. I want to give to Next a single expression, something like 'src/modules/*/pages/*', and let it resolve the pages and routes for me (like you would do in a ormconfig.json file to map entities when using TypeORM).
I suppose I could group my page components directly inside pages, like pages/a-module/*, but I also have components, hooks and other logic that I'd like to segregate into modules. I could also try using Node's fs to iterate through my project file structure and map the the page folders, but I'd like to avoid that if possible.
You could use symlinks. You would need one for each module, but not one for each nested path within the module. Your directory structure would look like:
├── modules
│ ├── bar
│ │ └── pages
│ │ ├── first.js
│ │ └── second.js
│ └── foo
│ └── pages
│ ├── first.js
│ └── second.js
├── pages
│ ├── _app.js
│ ├── bar -> ../modules/bar/pages
│ ├── foo -> ../modules/foo/pages
│ ├── index.js
Which would end up with routes:
/bar/first
/bar/second
/foo/first
/foo/second
I'm not sure what that buys you, though, really. Now your modules folder will have the same clutter that pages used to. You don't have to have all of the component content in the files in pages. It could be as simple as:
// pages/foo/first.js
import FirstContent from '../../modules/FirstContent'
export default function First() {
return <FirstContent />
}
As #Roman Mkrtchian mentioned, you're not supposed to do so. My suggestion is that, if you want to organize your files into modules like me, creating a file structure similar to this one:
src
├── modules
│ ├── foo
│ | └── pages
| | ├── one
| | | ├── index.jsx
| | | └── styles.js <- For `styled-components`; could be a css file
| | └── two
| | ├── index.jsx
| | └── styles.js
| └── bar
| └── pages
| └── three
| ├── index.jsx
| └── styles.js
├── shared
└── ...
You should take another approach. As #erich2k8 said, you don't need all of the component content to be in the files inside /pages, you could create the same structure above, but add /pages directly to src:
src
├── modules
├── shared
└── pages
├── foo
| ├── one.jsx
| └── two.jsx
└── bar
└── three.jsx
And inside src/pages/foo/one.jsx, for instance, you'd import src/modules/foo/pages/one, like so:
import OneContent from '../../modules/foo/pages/one';
const One = () => <OneContent />;
export default One;
Yes, you'd still need to create a new file for each page you create inside /modules, but it spares you from a really bad time messing with Next behavior.
This is not permitted by the Next.js team on purpose for reasons explained in this post and in the posts referenced there.
You may read some of the discussions before deciding if you really want to hack the files structure to do it anyway.
TL;DR - We have ran into an issue with Storybook inside of a Monorepo
whose packages are independently versioned where the problem surrounds
Storybook running out of memory when it tries to scan for
*.stories.js due to it scanning every package's node_modules
directory. require.context() doesn't allow for exclusion to the
point where it won't scan the node_modules directories and we
couldn't find a native webpack solution to this problem - nor could we
find any existing discussion points around this problem, whose
solution wasn't just require.context('.', true,
/^\.\/((?!node_modules).)*\.stories\.js$/). We're posting our
discovery and potentially solution to see if anyone in the community
has had to solve a similar problem, and see if we are missing
something/making it harder than it needs to be.
The problem that we are trying to solve for is that Webpack's require.context() method does not allow for excluding specific directories from being scanned. For our project set-up, we are utilizing Lerna to manage a monorepo a JavaScript packages that are all independently versioned. Our file tree looks like this:
.
├── config
│ └── storybook
└── packages
└── vue
└── components
├── example-component
│ ├── node_modules
│ │ └── ...
│ ├── test
│ │ ├── example.stories.js
│ │ └── index.spec.js
│ ├── index.vue
│ └── package.json
└── example-parent
├── example-component-2
│ ├── node_modules
│ │ └── ...
│ ├── test
│ │ ├── example.stories.js
│ │ └── index.spec.js
│ ├── index.vue
│ └── package.json
└── example-component-3
├── node_modules
│ └── ...
├── test
│ ├── example.stories.js
│ └── index.spec.js
├── index.vue
└── package.json
For our storybook configuration, we need to tell Storybook where each of the components' *.stories.js file lives. We want/need the solution to be dynamic in a sense where if we add a new component into the directory tree in the same fashion, Storybook should automatically find the new *.stories.js without having to update Storybook's config file.
The option that Storybook suggests, is to use the require.context(String directory, boolean isDeep, RegEx fileMatch) method that is a part of webpack. However, when isDeep is set as true you are unable to restrict the method from scanning particular directories, like node_modules, due to the fact that the directory parameter is a string and not RegEx. Understandably, a regex match for the directory would make this method more expensive. However, it means that even if I set up my method to look like require.context('.', true, /^\.\/((?!node_modules).)*\.stories\.js$/) WebPack is still going to traverse my node_modules directories but won't match any internal *.stories.js files.
This becomes an issue when we use Lerna to install all the packages' depenencies via lerna bootstrap. Since by default that command will install ALL dependencies, including devDependencies for stuff like automated tests, an individual node_modules directory for a component could be quite large. So as we are adding more and more components, we have ran into a memory issue with running Storybook when components have all of their dependencies installed.
Our initial band-aid solution, was to restrict Lerna from install devDependencies by using lerna bootstrap -- --production --no-optional however this makes us unable to run tests. To run tests, we then have to install all dependencies... which means we can't run Storybook until we clean up the node_modules.
Our current solution is to use a fs type of library/package that allows us to traverse the directory tree with more specificity, and manually ignore node_modules when scanning deep directories. This allows us to still nest components within parent directories for better organization of similar components, and still allows Storybook to automatically find new *.stories.js files. So now our story discovery and Storybook config looks like:
const path = require('path');
const directoryTree = require('directory-tree');
let isPopulatedDir = (item) => item.type === 'directory' && item.children.length > 0;
let isStoryFile = (item) => item.type === 'file' && /\.stories\.js$/.test(item.name);
function parseChildren(children, response) {
for(var i = 0; i < children.length; i++) {
let child = children[i];
if(child.name === 'node_modules') continue;
if (isPopulatedDir(child)) {
parseChildren(child.children, response);
} else if(isStoryFile(child)) {
response.push(child.path);
}
}
return response;
}
function getStories() {
const tree = directoryTree("./packages/vue/components"),
storyPaths = [];
tree.children.forEach(item => {
if (isPopulatedDir(item)) {
storyPaths.push(...parseChildren(item.children, []));
}
});
return storyPaths;
}
module.exports = {
stories: getStories(),
webpackFinal: async (config) => {
config.node = {
fs: "empty"
};
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve('./'),
];
// Return the altered config
return config;
}
}
This solution works, it doesn't traverse any node_module directories, and allow us to dynamically find the *.stories.js files, no matter how their directory may be set up. But we can't help but feel like this is a problem that other people have had to of ran into, and maybe we are just overlooking a solution that Webpack already offers. So please, if you have had similar obstacles to overcome whose solution may work better for us we'd love to hear your approach or thoughts on our solution.
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 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.