Urql: a GraphQL client library(formidable.com) |
Urql: a GraphQL client library(formidable.com) |
Apollo has also been moving in this direction with composable links, but in a zig-zaggy way since it's still got some baggage from its days as a monolithic library, and recent decisions to move local state management into core seems to be backtracking from that effort somewhat, so it's great to see some competition in this area that really approaches extensibility as a first class citizen rather than an afterthought.
With that said, I'd love to see an officially supported normalizing cache implementation as well, in addition to the simple document cache Urql currently provides as a default:
https://formidable.com/open-source/urql/docs/basics/#code-cl...
Apollo and Relay's normalizing cache helps ensure a single source of truth for every piece of server data, which is incredibly valuable for non-trivial apps that have the same pieces of data fetched in multiple places that would otherwise have to be manually kept in sync, which anyone who has ever tried to do so can tell you is generally extremely tedious, error prone, and likely a frequent contributor to user-facing bugs. That to me is by far the most compelling value prop of GraphQL clients like Apollo and Relay. It'd be great if I didn't have to choose between automatic normalization and a more flexible extensibility model (fwiw, I'd choose the former).
We've got the cache itself done but are just figuring out the API for its customisability in terms of cache resolvers and such
Great to see Formidable investing further in it, I am very excited to see first class extensibility.
How is that 22.5kB making any difference? Unless you are working on a project that will be used on very slow connections I see no point in choosing a library basing on such small difference in size. And if you really are targeting those slow connections then maybe going SPA is not the best choice?
If the bundle size is 550kb min/gzipped, that's 110kb of app code, and 440kb of dependencies. Some of the largest dependencies in a recent audit were: moment (60kb), swiper (32kb), lodash (24kb), react-select (26kb), raven.js (12kb), polyfills (25kb), mobile-detect (15kb), and then a bunch of smaller dependencies that made up the remaining 300kb.
Using this performance budget calculator you can quickly see how each 25kb of JS adds ~.3s to your TTI on a mobile phone:
https://perf-budget-calculator.firebaseapp.com/
If developers shop around for smaller alternatives of each dependency, then they can cut their load times pretty drastically.
It is not only about how long it takes to download, it is also about parsing that amount of code in low end phones.
MST and GraphQL together does sound like a pretty serious win
I've played with Relay (relay-modern looks great, but when I needed to pick a graphql client it hadn't been released yet). Apollo is frustrating: it's big and complicated and obsessed with stuff that I don't want (link-state and a bunch of product up-sells).
I'm glad urql is getting some more attention and I'll definitely give it a spin.
I hope SSR support is included soon!
Since we didn't want to go down the same road as some other libraries that use renderToStaticMarkup and a promise-queue, we've already built a supporting package so that we can implement SSR-support using suspense. (At least the unstable API of suspense; which is as simple for us as adding throwing promises to our components and hooks) https://github.com/FormidableLabs/react-ssr-prepass
Another example: Is `apollo-link-state` deprecated? The docs for `apollo-link-state` don't mention that, but the Local state management page in Apollo Client sure says it is.
const data = useQuery(url, graphql_query, variables)
The point here is that, the ApolloClient is lazily constructed and reused only when the hook is called.
I don't know why Graphql must be used with non-lazy url instead.
More than that, you don't need a Provider, because the apollo-client is reused between the calls.
I might try it out once it supports the new hooks.
honestly, it's my favorite stack nowadays.
Would like to know this also.
Your customer didn't write all the Apollo code. The docs feel like they are written with the assumption that we understand the architecture and goals as well as you do and we just want to do some simple task with it to get started. I fear however that this is fundamentally not a docs problem. It feels like a problem where the Apollo devs didn't start by asking "how can I build something that will be easy for 3rd party devs to use and understand", they started with "oooh that would be cool". Urql feels like it started with a very simple and clear conceptual foundation that provides a clear roadmap for how and where more complex features get attached.
If you can reduce Apollo down to a clear and simple framework in the docs that actually covers everything that it does, then you're golden. I suspect however that the underlying architectural simplicity that would be required for you to do this doesn't actually exist. If it does, you face a docs problem, if it doesn't, then docs are just a bandaid.
As a trivial example look at the documentation of client.query(), the most fundamental function. It lists the options for `errorPolicy` and `fetchPolicy` but doesn't explain them. The links lead nowhere (that's true for at least half the links on that page). You have to remember where to find that the Apollo React documentation instead. `fetchResults` is described like something that sounds like a boolean, but for some reason it has the type any. `metadata` is described so vaguely that I have no clue what it does. `query` is unhelpfully described as being of type `DocumentNode`. I'm left to guess that a gql string propably results in a DocumentNode, but I'm not sure everyone makes that deduction. `variables` is pretty much the only decently described parameter.
And that's for the simplest function. Just below that the `subscribe` function has a fetchPolicy parameter without giving any idea how fetchPolicies interact with subscriptions (how does a "cache-only" subscriptions work???). And I really hope I never want to directly use an ObservableQuery class, 7 of 11 members don't even have a description.
The documentation for the react stuff is mostly fine, but once you have to go beyond that you are on your own and end up reading source code to figure anything out.
Vue's documentation is a good example of the opposite, it feels friendly an accesible, it has a nice flow to it. Apollo has the opposite feeling even though everything seems to be documented and everything is explained.
Probable more an organization and presentation issue than a content issue.
Just my 2c.
I’ve also seen some erratic behavior from Apollo. While testing I found that Apollo deduplicates queries too aggressively. I made some mutations with slightly different inputs (think naming a new item “a” and another one “b”) and several of them would not get sent. In my example it would have resulted in two new items on the server but instead only one was created, because the second mutation wasn’t sent.
I also found that using the `called` flag in a mutation function child was basically useless because sometimes it would be false even if the mutation went through. I switched to using the onCompleted prop in the component and that’s worked.
Another thing I ran in to is that Apollo sometimes can’t update the store because I sent a query without an ID field. It throws an error. If an ID is required for all queries the docs should say so.
Also I don’t think the docs say that you should return any fields you update in a mutation, to make sure the store is current. I think I found that out on stack overflow.
- The `Query.skip` prop. I'd like to know all of the expected behavior for when this prop is used. For example, I've noticed that when skip is true then the render prop function's `data` object is always undefined, even though the data is there! Also when skip is true and you manually trigger a refetch elsewhere (for example when running a mutation with `refetchQueries` specified), the `onCompleted` prop doesn't get called, even though the query was in fact refetched and completed.
Those are just recent things I've noticed. Also for the record I don't mean to sound like I'm throwing shade. I appreciate all open source work and the Apollo projects are massive open source contributions, so thank you :)
Possibly this is just a doc issue but it seems like the API could benefit from some streamlining.
For instance, in the 401 logout example (https://www.apollographql.com/docs/react/advanced/network-la...), it imports a logout function from a separate module to call on 401, but I'd like to ideally have 401s trigger a change in some React state instead (possibly by passing through a state changing function as a prop to Apollo's Provider component?), and it's not entirely obvious to me from the docs how one would accomplish that.
Personally, I have no trouble with it’s usage since I have been dealing with it for 2 years, and I keep up with the GitHub changesets but new devs have a harder time on boarding since all the links on the site seem to lead to a framework specific documentation.
For example, Relay removes the need for a lot of Flux and network request boilerplate. Going beyond that, it can collapse serial network fetches down into one request, massively speeding up page loads.
(This doesn't apply to moment, that library is just designed in a brain dead way).
For skip, the behavior with refetchQueries sounds intentional since the refetching happens within the Mutation component. I don't think we pass information about whether the skip prop is set on the Query component to the refetchQueries array (https://github.com/apollographql/react-apollo/blob/master/sr...).
It’s not a simple key value cache, but a graph of values, which makes invalidation more complex but still in my opinion that is a huge oversight.
Hopefully an Apollo dev can give us some insight here: why is the cache a requirement? Why is it threaded into every bit of code? I’ve seen so many bugs from the cache, and I know there is a technical reason it has to be part of the core codebase, but I have forgotten why.
For what it's worth, we are rearchitecting parts of the cache to support invalidation and garbage collection for Apollo Client 3.0. The only reason why we don't have it yet is because it's a tough problem to solve - one mutation could invalidate an infinite amount of queries. We're committed to solving this soon though because we know the community really wants it.
It's been on my backlog for a while to rewrite the Apollo Client intro section to give developers the high level overview you're looking for. Now that Apollo Federation is out, I have some time on my calendar to do exactly that. :) Would you be open to reviewing the new section once it's done? If you're interested, send me an email at peggy [at] apollographql.com.
If it's still confusing after that, then we can chalk it up to a problem with the library. I suspect that it's a docs problem since the intro hasn't been overhauled since I joined the company almost 2 years ago.
they absolutely should. It's not really needed every time, but when you have a queries with IDs and without-that's when the cache blows up. They even a have a snapshot test for this unfortunate behavior: https://github.com/apollographql/apollo-client/blob/master/p...
Also IDs aren’t required for cache updates, only the typename.
this is very inacurate. The problem happens when an items is cached with an ID and then another GraphQL request tries to cache it without and ID or vice versa. This is where the apollo-cache-inmemory blows up with an error like this: https://api.media.atlassian.com/file/f82c0ee8-2412-4f1b-8027...
There's even a test for this unfortunate behavior: https://github.com/apollographql/apollo-client/blob/master/p...
The example to mind is last time I was trying to do something (a few months back) `apollo-link-rest` was highly recommended in the documentation as a potential solution, but yet visiting the GitHub for it seemed to be saying the exact opposite that it wasn't ready yet and was filled with massive API shifts and bugs/issues to iron out before "production ready".
Still I do think if you are building a web application (and not a static site or a blog) it is expected it can take a second or two to load it for the first time. 500 KB bundle is nothing wrong in that case.
It's also expected that my train is going to be late, but we can lament this condition, instead of resigning ourselves to it.
I would hate to use something built by people with the attitude that compromising on performance when you don't need to is OK because it falls in line with current expected ranges.
Ignoring the impact of libraries you send to the frontend will lead to death by a thousand cuts.