Skip to content

Instantly share code, notes, and snippets.

@bradparker
Last active August 2, 2017 04:45
Show Gist options
  • Save bradparker/679ad96aac848ca916facc450a8f91dc to your computer and use it in GitHub Desktop.
Save bradparker/679ad96aac848ca916facc450a8f91dc to your computer and use it in GitHub Desktop.
Project Structure

Modules example

A module which represents part of a Reaat app could export an array of routes and a reducer.

export {default as routes} from './routes'
export {default as reducer} from './store/reducer'

The top level application can take these exports and collect them together into the root routes def and the root reducer.

source
├── app
│   ├── components
│   │   ├── SimpleDonut
│   │   │   ├── __tests__
│   │   │   │   └── SimpleDonut-test.js
│   │   │   └── index.js
│   │   └── View
│   │       └── index.js
│   ├── lib
│   │   ├── getEnv
│   │   │   └── index.js
│   │   └── resolveAsset
│   │       └── index.js
│   ├── modules
│   │   ├── beneficiaries
│   │   │   ├── store
│   │   │   │   ├── __tests__
│   │   │   │   │   └── factories.js
│   │   │   │   ├── helpers
│   │   │   │   │   └── index.js
│   │   │   │   └── reducer
│   │   │   │       └── index.js
│   │   │   └── index.js
│   │   ├── campaigns
│   │   │   ├── store
│   │   │   │   ├── __tests__
│   │   │   │   │   └── factories.js
│   │   │   │   ├── helpers
│   │   │   │   │   └── index.js
│   │   │   │   └── reducer
│   │   │   │       └── index.js
│   │   │   └── index.js
│   │   ├── donations
│   │   │   ├── store
│   │   │   │   ├── __tests__
│   │   │   │   │   └── factories.js
│   │   │   │   ├── helpers
│   │   │   │   │   └── index.js
│   │   │   │   └── reducer
│   │   │   │       └── index.js
│   │   │   └── index.js
│   │   ├── errors
│   │   │   └── index.js
│   │   ├── fundraiserCampaigns
│   │   │   ├── components
│   │   │   │   ├── FundraiserSummary
│   │   │   │   │   ├── __tests__
│   │   │   │   │   │   └── FundraiserSummary-test.js
│   │   │   │   │   └── index.js
│   │   │   │   ├── FundraisingProgress
│   │   │   │   │   ├── __tests__
│   │   │   │   │   │   └── FundraisingProgress-test.js
│   │   │   │   │   └── index.js
│   │   │   │   ├── Summary
│   │   │   │   │   └── index.js
│   │   │   │   └── __tests__
│   │   │   │       └── helpers.js
│   │   │   ├── routes
│   │   │   │   ├── Show
│   │   │   │   │   ├── __tests__
│   │   │   │   │   │   └── Show-test.js
│   │   │   │   │   └── index.js
│   │   │   │   ├── __tests__
│   │   │   │   │   └── helpers.js
│   │   │   │   └── index.js
│   │   │   ├── store
│   │   │   │   ├── __tests__
│   │   │   │   │   └── factories.js
│   │   │   │   ├── actions
│   │   │   │   │   ├── __tests__
│   │   │   │   │   │   └── fetchFundraiserCampaign-test.js
│   │   │   │   │   └── index.js
│   │   │   │   ├── helpers
│   │   │   │   │   └── index.js
│   │   │   │   ├── reducer
│   │   │   │   │   ├── list
│   │   │   │   │   │   └── index.js
│   │   │   │   │   ├── show
│   │   │   │   │   │   └── index.js
│   │   │   │   │   └── index.js
│   │   │   │   ├── constants.js
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   └── fundraisers
│   │       ├── store
│   │       │   ├── __tests__
│   │       │   │   └── factories.js
│   │       │   ├── helpers
│   │       │   │   └── index.js
│   │       │   ├── reducer
│   │       │   │   └── index.js
│   │       │   └── index.js
│   │       └── index.js
│   ├── routes
│   │   └── index.js
│   ├── store
│   │   ├── reducer
│   │   │   └── index.js
│   │   ├── constants.js
│   │   └── index.js
│   ├── index.js
│   └── stats.js
├── client
│   ├── index.js
│   └── stats.js
├── config
│   ├── clientEnvRequirements.js
│   └── index.js
└── server
    ├── components
    │   └── Document.js
    ├── lib
    │   └── renderDocument.js
    ├── index.js
    └── stats.js

Organised by route-modules

All components and state specific to the /posts route can be managed in the routes/posts directory.

Module Exports

default

A route definition in whichever format react-router accepts. It might be nice to settle on the plain-routes format as it's likely to be more transferrable to other routers... this might be a silly thing to try and keep in mind.

reducer

If the app under this route is dealing with a specifc part of the state tree it might be a good idea for the route to export a reducer function to be included in the parent reducer.

Folders

/<route>/handlers

The module defined in routes/<route>/index.js may export multiple routes and therefore could have multiple route handlers. This is in opposition to having one handler per routes/<route> module, which could easily become impractical e.g. you may want a route per some kind of state under a resource: admin/posts/archived admin/posts/drafts. In that case it might be over-kill to add a new dir for each of these routes. By the same token the many exported routes may all use the same handler.

/<route>/components

Any components which aren't reusable outside of the scope of this route. This one will be tricky.

/<route>/store

All store related stuff whenever applicable (actions, reducer, and constants)

/<route>/routes

And down the rabbit hole we go.

Examples

source
├── components
│   └── Document.js
├── handlers
│   ├── Home.js
│   └── Root.js
├── routes
│   ├── posts
│   │   ├── handlers
│   │   │   ├── Post.js
│   │   │   └── Posts.js
│   │   ├── store
│   │   │   ├── actions.js
│   │   │   ├── constants.js
│   │   │   └── reducer.js
│   │   └── index.js
│   └── index.js
├── store
│   ├── index.js
│   └── reducer.js
├── utils
│   └── api
│       ├── fixtures.json
│       └── index.js
├── client.js
├── index.js
└── server.js

More nesting

source
├── components
│   └── Document.js
├── handlers
│   ├── Home.js
│   └── Root.js
├── routes
│   ├── posts
│   │   ├── components
│   │   │   └── PostAuthor.js
│   │   ├── handlers
│   │   │   └── Posts.js
│   │   ├── routes
│   │   │   ├── post
│   │   │   │   ├── components
│   │   │   │   │   └── PostComment.js
│   │   │   │   ├── handlers
│   │   │   │   │   └── Post.js
│   │   │   │   ├── store
│   │   │   │   │   ├── actions.js
│   │   │   │   │   ├── constants.js
│   │   │   │   │   └── reducer.js
│   │   │   │   └── index.js
│   │   ├── store
│   │   │   ├── actions.js
│   │   │   ├── constants.js
│   │   │   └── reducer.js
│   │   └── index.js
│   └── index.js
├── store
│   ├── index.js
│   └── reducer.js
├── utils
│   └── api
│       ├── fixtures.json
│       └── index.js
├── client.js
├── index.js
└── server.js
@benoneal
Copy link

benoneal commented Aug 9, 2016

As per our discussion Brad, I think the structure has a strong advantage in mapping to the url, so that maintenance/new features become easier to quickly find and work on. I think the name "routes" is a bit off, and the handlers folder is a bit confusing. I'd be most happy with this structure if routes predominantly contained components which delegate and manage data/entities/resources, while actual dom-rendering UI components were made more generic, in the top-level components folder (though under some sort of shallow logical grouping hierarchy).

@alexander-bobin
Copy link

As per Ben, I really like what this communicates.

Also think that handlers is kinda awkward although understand what you're trying to get at. Better as route-handlers at least. But it gets confusing when sitting next to another routes folder

@alexander-bobin
Copy link

I reckon we need to put our weight behind something and use it. We can adapt and revise as we go along. For me, we should use the above with the only change being clarification of handlers

@slwen
Copy link

slwen commented Oct 27, 2016

I don't think I have any feedback that hasn't already been raised, e.g. Making sure most purely UI components reside as high as possible in the tree in that generic components dir. On face value it appears fairly similar to the structure used by nexus, I would definitely like to throw it in to some projects and get a feel for it going forward. 👍

I guess the only other thing worth raising (which has been raised before) is how do we feel about using the ducks pattern for our Redux stores/actions/constants? Is there a particular reason you might have chosen to avoid that here @brad? I personally found it quite a nice pattern but honestly I'm not rolling with a lot of experience, just curious of your thoughts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment