Application Structure #27
Comments
mxstbr
added help wanted question
labels
Dec 17, 2015
|
Maybe we should have a folder called The structure of the boilerplate would then be as follows:
|
mxstbr
changed the title from
Moving all files possible to src folder to Application Structure
Dec 18, 2015
|
I believe having the The more I think about this structure, the more I like it. It makes using this boilerplate much easier and newcomer friendly. The structure would look like this:
|
|
Maybe Maybe |
swastik
commented
Dec 21, 2015
|
I think calling it
|
swastik
commented
Dec 21, 2015
|
Also, I don't think tests should go inside app. They aren't the "app", technically... nothing there would transpile to the final build. A separate tests folder is fine... it's also probably more visible. |
mxstbr
added a commit
that referenced
this issue
Dec 22, 2015
|
|
mxstbr |
4ed64ae
|
|
Good points. I've implemented this in the v3.0.0 branch, check it out and report any problems you come across! EDIT: Going to update the docs/FILES.md file soon. |
swastik
commented
Dec 23, 2015
|
Looks pretty good! |
mxstbr
added this to the
v3.0
milestone
Dec 24, 2015
mxstbr
self-assigned this
Dec 25, 2015
hampusohlsson
commented
Dec 26, 2015
|
You could consider bundling the actions, constants and reducers into redux modules and create reducer bundles according to the "ducks" approach. |
|
As discussed in #33, having a folder for "smart" components and one for "dumb" components makes a lot of sense. The question is where do pages fit in? I currently feel like this would be optimal - any other ideas?
|
|
@hampusohlsson thanks for the link, I'll look into it! |
hampusohlsson
commented
Dec 27, 2015
|
You can probably put it in a subfolder if you need it. However, my (rather limited) experience with this structure is that page components end up being the only smart ones in the entire app, so you can just keep them under |
|
I would actually be in favor of putting css and javascript. For example:
Since your build is a webpack bundle, it would also be cool to do this with tests as well. That would alleviate the need to have a |
|
I'm considering switching to this layout, as it makes a lot of sense for bigger applications. No
With CSS Modules importing the CSS files of each component in the Where do vendor CSS files and global CSS files (e.g. |
zavelevsky
commented
Dec 28, 2015
|
in that case - 'js' is not a good name for the parent folder |
|
True - any ideas for a better name for the parent folder? To be honest, I can't remember why I adopted that naming. Submitted a new issue for this, see #50 |
zavelevsky
commented
Dec 28, 2015
|
This is my project structure. Hopes it helps.
|
hampusohlsson
commented
Dec 28, 2015
|
As image assets also are part of the "source", I usually make one directory called // Importing a button from the IndexPage would look like this
import Button from '../../components/Button' and inside Button/index.js you would import the styles // Include the styles
import styles from './style.scss' Images would obvioulsy have to be imported from the assets folder import Icon from '../../assets/images/icon.png'Here's an example of how I've structured one project (a bunch of stuff omitted for brevity)
In the same manner, it would make a lot of sense to just add a file called Re the global css; right now I'm combining the scss files that contains overall layout, variables and typography into one scss file called |
|
@zavelevsky that's very helpful, thanks! What do the @hampusohlsson We have the This is what I'm currently looking at:
Still not sure what to rename the |
hampusohlsson
commented
Dec 28, 2015
|
@mxstbr did not know about enzyme, looks good! Regarding the renaming of the folder, I think it is hard to satisfy all developers, but I would not recommend using |
|
A few thoughts later:
Main changes:
This one is much cleaner and smaller, while keeping the functionality fully intact. The only question remaining for me is, where do we put |
|
I just noticed that EDIT: Also, we should add a
|
mxstbr
added a commit
that referenced
this issue
Dec 28, 2015
|
|
mxstbr |
1463490
|
|
I've switched the |
hampusohlsson
commented
Dec 29, 2015
|
Hey @mxstbr, some first impression feedback on your structure. What is the reasoning behind having the HomePage{action,constants,reducers} together with the component (btw, using the ducks approach you would combine everything in one file)? What if you want to dispatch a common action that lives in the HomePage folder from another component, then you would have to either duplicate the actions or remember which component has the actions and include that.. feels a bit dirty Also, I would not put the redux root-reducer in the same folder as the css (why not put the css folder inside assets :) images are "global" too in a sense, as they can be included from anywhere). A suggestion is to rename
In this case your root reducer could look something like this import { combineReducers } from 'redux';
import { routeReducer } from 'redux-simple-router';
// Custom reducers
import HomePageReducer from './HomePage/HomePage';
// Combine all into one
export default combineReducers({
HomePage: HomePageReducer,
routing: routeReducer
});
// Expose individual reducers
export const HomePage = HomePageReducer;This would allow you to use the following imports // Import HomePage reducers
import { HomePage } from '../reducers'
// Import the root reducers
import RootReducer from '../reducers'I know you are not too fond of naming files |
|
@hampusohlsson thanks so much for checking it out and posting this amazing feedback! You're right about, I'm not fond of the I agree that the root reducers shouldn't be there either, I'm just going to put it in the root next to the The reasoning behind having the {actions,reducers,constants} in the same folder as the component: Imagine you have a import { openNav, closeNav } from '../NavBar/NavBarActions.js';Now you can open and close the NavBar from the HomePage! Which (in my mind) makes a lot of sense. The I'm not sure one should ever have global actions. Do you have an example of an action that doesn't belong to a specific component? |
hampusohlsson
commented
Dec 29, 2015
|
@mxstbr in your case, I agree it makes sense to put the navbar specific actions together with the An example I'm thinking of is where you need to fetch/update a bunch of data from the server, e.g. populating a list of users. This list of users could be rendered in multiple components, and actions taken on that list from multiple places. Not sure where that kind of functionality should go. Perhaps it is the same discussion as with global css |
zavelevsky
commented
Dec 29, 2015
|
I strongly advise against mixing redux actions with components. You should
|
|
@zavelevsky interesting, I don't fully agree though. (to be clear, I'm unhappy with the current As shown above, you can easily import a The problem of global actions/reducers/..., like the very common data-fetching pattern, still persists. Maybe we could rename the current |
zavelevsky
commented
Dec 29, 2015
|
Additional arguments against placing actions with components :
|
hampusohlsson
commented
Dec 30, 2015
|
@zavelevsky thanks for pointing our the difference, did not think about top-down vs bottom-up approach before. Top down is what makes sense to me, keeping all state management code together. |
vramana
commented
Dec 30, 2015
|
I started out with a containers and dumb components approach but it didn't scale well as kept adding more and more routes and subroutes. My dumb components folder grew too much that it takes a few seconds for me find what I want. I think the approach proposed by @ryanflorence https://gist.github.com/ryanflorence/daafb1e3cb8ad740b346/ works best when you are building a large app. |
|
@vramana agreed, that looks very nice for massive apps, but I think it's too convoluted for small to mid size apps. There's gotta be a middle ground somewhere which works for small apps and scales well... |
CrocoDillon
commented
Dec 30, 2015
|
While I agree with the arguments against placing components together with redux stuff there are arguments for as well. If you want to consider large apps I imagine you want to keep stuff modular so different people can work on different parts of the app. Where I work for example each part (called a widget) lives in its own repo with its own template, js, css and tests. We have close to 100 widgets. Nothing React/Redux though but just as an example. A setup like this not only enables multiple repository for large companies but also enables sharing over npm for anyone. I'm not sure yet what folder structure I prefer, just saying there are arguments for both :) |
vramana
commented
Dec 30, 2015
|
@mxstbr Then it should be noted in the README that this might not be the right architecture for starting massive applications. Otherwise they will have to lot of refactoring like me if they every want to switch. |
|
To elaborate on my short reply above: I tend to agree with @zavelevsky that a top-down approach makes more sense when thinking in Redux, so separating the actions, constants and reducers from the components might not be a bad idea after all. This would also allow for global actions, constants and reducers, e.g. for data fetching. Example:
I still believe the separation of stateful and stateless components makes sense, but I also believe it doesn't scale very well. (like @vramana said above) Does anybody have an idea how to combine those two approaches to create a new structure? (Or maybe throw away both of them and create a new one?) |
ezekielchentnik
commented
Dec 30, 2015
|
I prefer to keep it simple and consistent. I also like matching typical flux folder structure for easy mapping of concepts (facebook examples). My boilerplate is meant to be used to keep consistency across apps spawned by multiple separate teams. I also have to teach/train devs. Also, if someone prefers Alt.js, or pure flux as opposed to redux, for the most part, the folders will map and make sense, less cognitive overload... in other words, from react/flux implementation to implementation there is some consistency. the /dist folder is also important, it looks like a normal static website folder. of course, we're also not generating universal apps, but SPAs, and have multiple platforms the apps need to live on, so producing a static /dist that is portable, is important.... hope this helps. https://github.com/ezekielchentnik/react-redux-boilerplate ├── dist # built dist, can live anywhere (node, http://surge.sh/, whatever ...)
│ └── css
│ └── images
│ └── js
│ └── index.html
├── src # source
│ └── css # css/sass, compiled w/postcss
│ └── images # .png,.svg,.gif optimized w/webpack
│ └── js # react/redux source
│ ├── actions # redux actions, w/thunk
│ ├── components # react components
│ ├── constants # constants
│ ├── containers # containers
│ ├── reducers # reducers
│ ├── selectors # selectors, using reselect
│ ├── store # store, w/devtools & prod config
│ ├── utils # utilities/helpers, support immatable
│ └── index.js # app entry
│ └── index.html # app shell
├── test # tests
│ └── *.js # specs
│ └── setup.js # jsdom config
├── .babelrc # babel config
├── .eslintrc # eslint config
├── .gitignore # git config
├── devServer.js # webpack/express dev server
├── LICENSE # license info
├── package.json # npm
├── README.md # installation, usage
├── webpack.config.dev.js # config for dev, hot loading, devtools, etc.
└── webpack.config.prod.js # config for prod, minification, etc.
|
vramana
commented
Dec 30, 2015
|
@mxstbr If you think about it ryan's approach works for small apps as wells we just need not show all that nesting. We just stop at the first level. |
ezekielchentnik
commented
Dec 30, 2015
|
i agree with @CrocoDillon comment, if there are truly sharable components, treat as such. |
|
I think the latest structure above is quite good. It works for small applications, preserves the differentiation between stateful and stateless react components, and, for larger applications, switching to the nested structure by @ryanflorence is trivial. (Rename root I've been thinking about the naming of the a/c/r. We could name the a/c/r with a dot in the name, e.g. import reducers from "./**/*.reducer.js";
import { combineReducers } from "redux";
const rootReducer = combineReducers(reducers); // Haven't tried this, but it should work
export default rootReducer;Which means new reducers are automatically added to the store. More magic for beginners, but a bit of a time saver and easily explainable. I'm still on the verge about putting the actions/constants/reducer (a/c/r) next to the container. import { openNav, closeNav } from "../NavBar/NavBar.actions";On the other hand, global a/c/r won't have a place to be. I think putting the a/c/r next to the container and introducing a Putting all of those thoughts together leaves us with this app structure:
Thoughts? |
babeard
commented
Dec 30, 2015
|
Are there any drawbacks to having a less verbose structure? It seems a little redundant to have a file named NavBar.actions.js already residing within the NavBar directory. Thoughts?
(sorry if this has already been discussed and explained elsewhere) |
|
@babeard I don't think it has, thanks for pointing that out! I'll tell you my reasoning: If you open two
|
zavelevsky
commented
Dec 30, 2015
|
I have to say that the feature separation is a weak argument IMO. Cross I think it will make the initial project structure much easier to grasp. Having said that, in case my opinion isn't accepted, I think your proposal
|
babeard
commented
Dec 30, 2015
|
@mxstbr Good point. And of course this kind of decision can be made when you create your components. I personally prefer typing less by default. import { action } from "../NavBar/actions";
// vs
import { action } from "../NavBar/NavBar.actions";Keep up the good work! |
mxstbr
removed their assignment
Dec 30, 2015
hampusohlsson
commented
Dec 30, 2015
|
@babeard like you, I also think it is too verbose to name both the folder and the files the same thing. Also, how about the ducks approach? Curious what is the benefit of having 3 separate files or folders for actions/constants/reducers? |
CrocoDillon
commented
Dec 31, 2015
|
@babeard and others, whatever the file names in the import NavBar, { reducer, action } from '../NavBar'; |
|
@zavelevsky yes, the current structure is "more standard", that's true - that doesn't mean it's the best approach possible though. We now have to opportunity to influence the way redux applications are structured, and I want to make sure we get this right. I don't agree stateful components won't be reused - imagine a common @hampusohlsson While the ducks approach is quite nice, it's unusual and most redux tutorials will teach you to keep these variables in different files. Suddenly having all of them in one file might confuse beginners, especially with the very specific This reminds me, the whole Note: I've opened a Gitter chatroom for quicker discussions, join here! |
hampusohlsson
commented
Dec 31, 2015
|
Regarding the current state of redux tutorials, what I found out in November is that the tutorials from September were already outdated. The ecosystem is moving crazy fast and I don't think we should get stuck in previous best practises. Keep pushing everything forward instead! Will check out the gitter chatroom next week, nice one. |
|
@hampusohlsson that's true. Hmm... |
|
I'm confused as to why Components and Containers need associated Actions to them. They aren't 1:1 mapped (in the way that a component would have tests only for it, or styles only for it). Multiple different components could trigger an action, as well as your something in async middleware... I would keep them in their own folder. |
|
@philihp That's true, but as I posted above, imagine a NavBar component that has an import { openNav, closeNav } from "../NavBar/NavBar.actions";instead of import { openNav, closeNav } from "../.. /actions/NavBar.actions"; |
mxstbr
added a commit
that referenced
this issue
Jan 3, 2016
|
|
mxstbr |
072ad9b
|
|
@hampusohlsson I've tried the ducks approach, and decided against it. The confusion caused by the very specific needs of that file are too unusual. In the coming days I'll try to build something with the new application structure to get a feel for the usability. (TBD what) If anybody else has tried it and built something with it, I'd love any and every input/criticism/comment!
|
canvaskisa
commented
Jan 7, 2016
|
Hey guys, i'd like to share an application structure i've created and working with for a while. I found it very scalable and simple to understand. I'm using css-modules, so i can keep component's styles in the same directory as component's logic is (the same is for components tesing).
I reduced project's tree a lot, but i think it's clear to understand the base concept. |
|
@canvaskisa thanks for sharing, I have not seen this split between What exactly are the benefits of this classification? It seems a bit... wobbly, for the lack of a better word. (In the sense that it seems hard to draw an exact line between |
canvaskisa
commented
Jan 7, 2016
|
@mxstbr Currently i'm working on media apps, and this structure simplifies development lot, in my experience. Of course you can remove such concepts as The main concept is to beware flat structure of your components, categorize them with reusable components ( import { Footer } from 'Modules'; Also i'd like to add, that i don't think moving stateful components to containers folder is a good idea. It makes directory structure flat, which is bad, in my opinion. |
|
@canvaskisa interesting! How do you get those clear imports, did you use Why do you believe a flat directory structure is inherently bad? |
canvaskisa
commented
Jan 7, 2016
|
@mxstbr Yeah,
On the server setting Flat directory structure is ok, but only for small apps. When an app is getting bigger, it's a pain to maintain it with flat structure. |
ravinggenius
commented
Jan 19, 2016
|
I'm new to this project, so I may be missing something obvious. However I'd like to suggest merging
|
|
@ravinggenius The problem is that you need some sort of separation between components. If you're building a big application, some day you'll have hundreds of components and having them all in one folder is a pain. I like the |
|
I didn't read it carefully so I might miss something but it seems this thread is mostly concerned about JS and not taking in account CSS and images. I'm strongly against putting CSS and Take a look at BEM: https://en.bem.info/method/filesystem/ — this is the idea behind CSS-modules. |
|
Yeah, CSS will be next to the JS files. Take a look at the |
|
Yes, I saw that and that's cool. But what about non-CSS assets? You still have |
|
I didn't think about images at all, but that makes sense. I also think @CrocoDillon and @hampusohlsson were right. I'm not fond of the file-naming anymore:
I now much prefer this, as its much nicer to
This means you can just go |
|
@mxstbr check mxstbr#103 out I think verbose file names are good because you'll be looking for stuff in IDE/editor by the name. But to reduce code for imports you could just use |
CrocoDillon
commented
Jan 19, 2016
|
@okonet, I already mentioned the use of It got overlooked though ;) Whatever the file names are I recommend this approach because you’ll have all exports for a module nicely listed in one small file ( |
|
Yeah, you were right it is so much nicer to name them |
hampusohlsson
commented
Jan 19, 2016
|
@mxstbr glad you have realized the naming benefit of |
|
I put the actual components in the
I still consider that in bad editors users won't be able to differentiate between the Does anybody have comments about the app structure, something they dislike? Otherwise I'll consider this issue resolved & will close it. |
|
@mxstbr it's not about showing path but about searching for a file. If you know you want to open |
|
@okonet Ah you're right, I totally forgot about that, damn. Too many reasons for too many things to keep track of... Thanks for reminding me, I'll have another think about it! |
ravinggenius
commented
Jan 21, 2016
|
@okonet Vim/Sublime/Atom each can find files via (case-insensitive) fuzzy searches. For instance you can type something like |
|
@ravinggenius just my personal experience: we always have a couple components with similar names: |
|
I agree with @nikgraf, especially if you're going with the "hardcore" containers there'll be lots of overlap between names. I just don't think that adding a That doesn't really make a difference, but not having to add an "unnecessary" file each time you create a new component does make a difference, esp. for consistency with multiple devs, so I'm leaning towards the |
|
I've decided to go with the I've been working with the boilerplate (non- |
mxstbr
closed this
Jan 23, 2016
This was referenced Jan 29, 2016
nareshbhatia
commented
Jun 12, 2016
|
Sorry for jumping in late, but as I am starting to understand react-boilerplate, I wanted to suggest an alternate approach to application structure that might be more intuitive. This is what we currently have: all container components under Instead of breaking things by type, wouldn't it be better to break things by feature? Using this approach, the Dashboard component will be a top-level folder with the 6 presentational components under it as 6 child folders. If there is a strong need to distinguish container components from presentational components, the developer can follow some naming conventions similar to those suggested by Dan Abramov in his article, e.g.
This seems much more intuitive to me because it keeps all related components together. What do you think? |
oyeanuj
commented
Jun 12, 2016
|
FWIW, I have a structure similar to one mentioned by @nareshbhatia except for one change - instead of having a Shared folder, I have the shared components grouped by type of functionality provided by those components, i.e. Buttons, Forms, Cards etc. Currently using it on a medium-large scale application and has scaled well and made my life easier. |
nareshbhatia
commented
Jun 12, 2016
|
Good to know, @oyeanuj. I have been googling for articles on application structure best practices. Here's two that I found to be very good:
|
mxstbr commentedDec 17, 2015
Changing the application structure might be worth thinking about, right now the thing might seem quite bloated and randomly thrown together for newcomers.