mattkrick / cashay

:moneybag: Relay for the rest of us :moneybag:
MIT License
453 stars 28 forks source link

Plans for colocation? #35

Closed jsierles closed 8 years ago

jsierles commented 8 years ago

First just would like to say this project looks great! Just wondering if there are plans to make colocation possible - this is a huge feature of Relay. And if so, where might be a good starting point to look into support?

mattkrick commented 8 years ago

Good call opening an issue on this, it's definitely on the roadmap, although after #27 subscriptions & #23 TTL. It's definitely going to be a front-end specific package to keep the core small and front-end agnostic. For now, you can still colocate your queries, you just have to make em smaller (maybe I should say Cashay lacks "query aggregation" instead?). Ideally, I really want to build a tool that climbs down your tree, collects whatever you need (in this case, query fragments) and then climbs back up to the parent. If you use a CSS library that works server-side, it already does exactly this, it just grabs inline style fragments instead of query fragments. Why not have 1 tool that can serve both purposes? The entity that's causing this pain in react is that there's no concept of a component location. 1 component has many locations in the tree, and 1 location can have many instances. If a user builds a static tree (similar to a react router tree, but deeper than just the route level) then the router, css aggregator, and query aggregator can all use it.

The tool (let's call it react-tree-climber) would be simple enough. It takes in a sitemap.js. For the routes, it spits out the equivalent of a routes.js. For CSS and queries, react-tree-climber would have a plugin for Cashay and, eg react-look (inline CSS library). Those plugins are just functions that take in an object & at every node of the tree, it grabs what it can. We could take a page out of the GraphQL book & use the visitor pattern to do this, as it lends itself well to accepting multiple visitor functions so you only climb the tree once (https://github.com/graphql/graphql-js/blob/master/src/language/visitor.js).

If you'd like to take a crack at it, I'd be happy to help, but I just can't justify the need to be super critical since if I need colocation, I can just make 2 smaller queries. I've never come up against the HTTP/1.1 request limit, so it's more of a nice-to-have.

mattkrick commented 8 years ago

CC @gaearon, i know there was talk about facebook doing something to fix this internally in the react codebase (so SSRing CSS code is easier and Relay containers are less awkward when climbing down children), but never saw more than chatter. Any word if something might be in the works at facebook for react to make this easier?

jsierles commented 8 years ago

Good points you make there. Part of the appeal of new approaches like this is that sometimes the discussion around Relay confuses these points, like colocation and aggregation. I'll have to give it a try and see.

Would the mean that right now, on an initial load, if various components in a tree share a need for the same data, they might end up issuing queries for duplicate data in parallel?

mattkrick commented 8 years ago

correct, Cashay doesn't handle pending queries. I actually experimented with that when building it, but it adds a huge amount of complexity due to abstract classes (unions) and pagination, as the store would always represent all possible future states (ie the 5th dimension) instead of the actual current state, so it's a slippery slope.

The benefit for all that extra complexity is theoretically a handful of bytes saved on the initial payload, but in reality, since the result (rootCall in Relay terms) is different, you actually wouldn't save anything. For example, a client cache can't know that both getPosts and getTop5Posts will return post#123, so it'll return that item twice, even if you did aggregate the queries. This affects Relay, too. In such cases, you have 2 options:

gaearon commented 8 years ago

What kind of API do you envision React could provide for this?

mattkrick commented 8 years ago

@gaearon I'm not sure what the API would look like yet, but I think the first step would be to add the concept of Location so instead of just accepting that 1 component has many instances, 1 component would have many locations, and each location would have many instances. Then, from a Location we could infer the parent Location (and therefore component), which would make climbing back up really simple. I'll give it some more thought later, I thought i read that facebook was already thinking about something like this (maybe in the Relay issues? couldn't find it again).

abhishiv commented 8 years ago

Sounds really great, I'm doing something similar but in a different context - visual builder.

Am I right to think that I can also theoretically statically analyzing source code to come up with data requirements automatically?

mattkrick commented 8 years ago

@abhishiv nope, you can get close, but consider {this.props.foo ? <Foo/> : <Bar/>}. You'll still need to manually write out your entire app tree, but your routes.js should get you more than half way.

mattkrick commented 8 years ago

Closing as Cashay offers colocation, but I don't think Cashay will ever offer query aggregation inside the package itself.

A couple definitions:

Colocation is already possible by simply using cashay.query in your view-model layer (eg in the mapStateToProps that sits on top of your container). You can make these as small as you want, just follow the guidance set out by redux on when to use connect.

However, query aggregation doesn't save you any round trips, because you can't know what the child needs until you know what the child is. How you group queries is dependent on your front end, and therefore should stay out of scope of this package (do 1 thing...).