redwoodjs / redwood

The App Framework for Startups
https://redwoodjs.com
MIT License
17.31k stars 995 forks source link

[RFC]: New file organization scheme for components used by only a single parent #10263

Open cannikin opened 7 months ago

cannikin commented 7 months ago

Summary

After five years of building Redwood apps, patterns have emerged when it comes to organizing the components that make it up. One is that we'll often have components that are only used by a single parent, not shared with others. We've found that co-locating those components with the parent is a great way to stay organized. What does the community think about making this a standard going forward?

Motivation

To keep our apps better organized for long term maintenance.

Detailed proposal

The top level /components directory would be used for components that are shared by two or more parents, otherwise they would go next to their parent layout/pages in the /layouts and /pages directory.

Imagine an application which has a page listing products, a Cell which actually fetches and displays those products, a component for adding a product to the cart, and the actual button the user clicks. The button would be shared across the app, but the <ProductsCell> is only used by the <ProductsPage>, and <AddToCart> is only used in <ProductsCell>:

Before

.
├── components
│   ├── AddToCart
│   │   └── AddToCart.jsx
│   ├── Button
│   │   └── Button.jsx
│   └── ProductsCell
│       └── ProductsCell.jsx
├── layouts
└── pages
    └── ProductsPage
        └── ProductsPage.jsx

After

.
├── components
│   └── Button
│       └── Button.jsx
├── layouts
└── pages
    └── ProductsPage
        ├── ProductsCell
        │   ├── AddToCart
        │   │   └── AddToCart.jsx
        │   └── ProductsCell.jsx
        └── ProductsPage.jsx

Are you interested in working on this?

dustinsgoodman commented 7 months ago

Let's say you have a UserCell that's shared on different pages, would that still go in components? If so, I think this is a wonderful pattern to consider. We use this in other project structures for the same reason and I use it on all my Redwood projects.

cannikin commented 7 months ago

Yep, as soon as it's shared with another parent, it would go in web/src/components instead of the parent's directory!

ValentinH commented 7 months ago

Colocation FTW!

simoncrypta commented 7 months ago

I use this file organization scheme for years, it is a great way to keep organizing when the project and team scale. At LeftLane we also have domain directories focused by type of end user, think about front-desk/back-office kind of separation. Again, everything works, just need to add the directory name into the Route page import. I'm curious, what's the plan by going with this new file organization scheme by default in RW? One request I hope for is to be able to select the page I want my component to be generated with the CLI.

cannikin commented 7 months ago

One request I hope for is to be able to select the page I want my component to be generated with the CLI.

Yep we'll have to re-think the generators and maybe some new args that can be passed to them letting them know you want to generate them next to some existing pages, instead of always in their root directory like /components.

My first instinct was that you include the path where you want it generated, otherwise it'll go in the default location:

yarn rw g component Button
# web/src/components/Button/Button.jsx

yarn rw g component Button AdminPage
# web/src/pages/AdminPage/Button/Button.jsx

yarn rw g component Button AdminPage/UsersCell/UserRow
# web/src/pages/AdminPage/UsersCell/UserRow/Button/Button.jsx
simoncrypta commented 7 months ago

My first instinct was that you include the path where you want it generated, otherwise it'll go in the default location:

yarn rw g component Button
# web/src/components/Button/Button.jsx

yarn rw g component Button AdminPage
# web/src/pages/AdminPage/Button/Button.jsx

yarn rw g component Button AdminPage/UsersCell/UserRow
# web/src/pages/AdminPage/UsersCell/UserRow/Button/Button.jsx

I would prefer to start from ../src for more flexibility, for example, we would like to do things like that :

yarn rw g component Button pages/dealership/components
# web/src/pages/dealership/components/Button/Button.jsx

yarn rw g component Button pages/admin/User/EditUserPage
# web/src/pages/admin/User/EditUserPage/Button/Button.jsx
Tobbe commented 7 months ago

yarn rw g component Button AdminPage/UsersCell/UserRow

I really like how this gives more flexibility to our users! But I'm a little concerned about DX

Because there's no auto-complete when writing the path here there's a lot of room for typos and/or just not remembering exactly what you named things. Discoverability is also not great.

Anyone have any thoughts on how to mitigate those concerns?

cannikin commented 7 months ago

If we just start the path from the current directory, you would get the standard shell autocomplete:

yarn rw g component Button web/src/pages/AdminPage/UsersCell/UserRow
colbywhite commented 7 months ago

this is typically the same comp structure i personally use. and thus i like this for standard selfish reasons

but i'd vote to default to this but then provide the tools for ppl to swap back and forth, which is a little bit different than generating a comp in one style or the other. inevitably my comps start out for a specific page then i realize i need it to be shared 2 months later. and vice versa. maybe something like yarn rw g comp mv MySharedComp ProductPage and it fixes the imports and maybe even renames the comp (both in the filename and the file itself).

a linter that lets me know that my shared comp isn't actually shared would also be cool. maybe even more valuable. especially if it can autofix itself by moving the comp itself.