Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

urql v3 Major Releases: ES2015+ and more! #2621

Closed
kitten opened this issue Aug 19, 2022 · 11 comments
Closed

urql v3 Major Releases: ES2015+ and more! #2621

kitten opened this issue Aug 19, 2022 · 11 comments

Comments

@kitten
Copy link
Member

kitten commented Aug 19, 2022

As part of the latest major releases across all packages we'd like to highlight some of the differences and provide some context and instructions around this release!

Backwards Compatibility

urql has always been architected to be a "stable core" project. This meant that the architecture, as we first set it has seen very little change since the inception of the project.

We still stand by this and would like to highlight that the coming major releases still remain mostly backwards compatible.

We make some exceptions here, and all breaking changes are listed later. However, while Wonka has been updated to v6, all your exchanges and usages of the Client should mostly remain unchanged!

While we're avoiding breaking changes as much as possible (and even more so when it comes to our core architecture and protocols), we're taking this opportunity to introduce some breakage to clean up old behaviour we wanted to adjust and tweak for a while.

First up, we do recommend you to upgrade all packages at once, however, you'll also able to upgrade partially. All exchanges and packages remain intercompatible across versions, and you'd only be duplicating the wonka package.

Client and Exchanges

No internal API contracts have been broken, and exchanges and how they interact with the Client still remain the same.

Wonka and Streams

If you only upgrade some packages you may temporarily have two installations of wonka, namely wonka@4.0.15 and wonka@6.0.0.

Wonka is a streaming library, inspired by the Callbag specification, similar to Observables, but written to be more minimal and small in size. It drives our internal logic in the Client, how you interact with it, and how exchanges work.

Both versions are 100% intercompatible and can coexist in the same app. Its internal data structures and API contracts have also not changed.

Wonka has been rewritten in TypeScript to ensure its future longevity and make it more beginner friendly to new contributors. It was previously written in ReScript/ReasonML, an OCaml derivative and compiled with BuckleScript to JavaScript.

Breaking Changes

We'd like to take a second to highlight the changes that definitely are breaking and that you should take special note of.

Goodbye IE11 / Targeting ES2015

Most importantly, in this batch of releases, we're deprecating our support for Internet Explorer 11 and are instead targeting ES2015+ from now on. This will likely not affect you to much.

If you want to compare what we support to what you support, we're basically sticking to evergreen browsers with some exceptions. In a browserslist rules format this looks like this:

last 3 ios_saf versions
last 3 and_chr major versions
op_mini > 99
and_uc > 99
last 3 samsung major versions
last 3 opera versions
last 3 safari versions
last 10 chrome major versions
last 8 firefox major versions
ie > 99
last 3 edge versions

The tl;dr of the above is that we support ES6 / ES2015 and that you should expect our code to not work in Internet Explorer 11 any longer. Other browsers like Chromium, Firefox, and Safari are therefore unaffected.

Stricter Variable Types

Previously, if you've used type generatords (like GraphQL Code Generator with a React hooks output for TypedDocumentNodes) you were unfortunately able to leave out variables from your GraphQL operations when passing in the query argument.

This was a mistake and we're explicitly removing this behaviour. We're now enforcing client.query(query, variables) to require variables when the query is typed.

Graphcache Optimistic Updates

When writing optimistic updates, you previously had to match your optimistic objects to the field aliases of the mutation that you defined. This was our previous mechanism to ensure that you could support multiple mutations with different selection sets.

This was a poor workaround and instead, we now properly look every field up by its name in your optimistic objects, as you'd expect, since it matches the behaviour of resolvers.

You may still support multiple mutations with different selection sets by passing in nested optimistic functions in your optimistic objects! In short, this is now possible:

cacheExchange({
  optimistic: {
    favoriteTodo(variables, cache, info) {
      return {
        __typename: 'Todo',
        id: variables.id,
        // You can dynamically return values here:
        favorite(args, cache, info) {
          return true;
        },
      },
    },
  },
});

Graphcache's Offline Rehydration

Previously, Graphcache would block all operations while it's rehydrating from its offline storage. Our default storage strategy is based on IndexedDB and your alternative storages (for instance for React Native via @urql/storage-rn) may also be asynchronous.

To deal with this we used to queue up operations and would only allow execution to continue once rehydration was complete. However, this made server-side rendering rehydration impossible, as it'd interfere with the first render.

We now instead eagerly execute operations, even sending network requests as necessary and "race" the offline storage against network requests.

Slimming down the Client

@urql/core's Client, the centre of all GraphQL operations, previously had a lot of properties and methods it didn't need anymore, which were leftovers of its first implementation, believe it or not.

Since, they weren't used a lot and are just sitting there, waiting to be monkey-patched in unintended ways, and are just adding to our bundle-size, we've removed them. They were already not documented before, but we still waited for a major release to fully get rid of them.

The properties that are now gone are:

  • Client.createOperationContext()
  • Client.url
  • Client.fetch
  • Client.fetchOptions
  • Client.maskTypename
  • Client.preferGetMethod
  • Client.requestPolicy

Accept for the first one here, as you can see, all of these were ClientOptions that were copied over to the Client instance and could be modified on the fly. This wasn't an intentional feature, and we now recommend you to instead use the new @urql/context's contextExchange instead, if you reply on updating any of the OperationContext options dynamically.

ClientOptions.url is assumed to be a URL

In previous versions of urql we refrained from doing anything fancy to the url option that was passed in. It'd simplt end up being what fetch(url) would be called with.

However, when we in the past introduced preferGetMethod and @urql/exchange-persisted-fetch this meant that GET methods were becoming part of @urql/core. This in turn meant that URL manipulation became necessary.

In this major release of @urql/core we've switched over to using the Web Standard built-ins URL and URLSearchParams. This is less error prone. (Previously we didn't support preferGetMethod being enabled while search parameters were passed to ClientOptions.url, for instance)

As the name implies, ClientOptions.url was always meant to be a qualified URL, but '/graphql' (in fact, not a full URL) made its way into several parts of the documentation.
We do in fact recommend to always construct a full URL string before passing it to urql.

At the very least, passing '/graphql' can be replaced (when no server-side use is involved) with new URL('/graphql', document.location.origin).toString().

Edit: We forgot to mention this breaking change on our list currently. But you'll only run into it if you're using GET methods with GraphQL

Removing Granular Imports

Previously, we used to resolve imports from graphql in our output bundles to granular imports. This meant that our bundles could contain imports like:

import { visit } from "graphql/language/visitor.mjs";
import { Kind } from "graphql/language/kinds.mjs";
import { print } from "graphql/language/printer.mjs";

While this was great for bundlesize, at least for bundlers that failed at correctly treeshaking graphql, it wasn't great for our Node.js support.

That's why we're removing this, and if you rely on treeshaking to work correctly, please make sure that your bundler is able to only leave around the parts of graphql that you're actually using.

Alternatively, you could alias graphql in production to graphql-web-lite.

@kitten kitten pinned this issue Aug 19, 2022
@kitten kitten changed the title Breaking Changes: ES2015+ and more! urql v3 Major Releases: ES2015+ and more! Aug 19, 2022
@onionhammer

This comment was marked as off-topic.

@JoviDeCroock

This comment was marked as off-topic.

@onionhammer

This comment was marked as off-topic.

@kitten

This comment was marked as off-topic.

@onionhammer

This comment was marked as off-topic.

@onionhammer

This comment was marked as off-topic.

@kitten

This comment was marked as off-topic.

@onionhammer

This comment was marked as off-topic.

@kitten

This comment was marked as off-topic.

@onionhammer

This comment was marked as off-topic.

@kitten
Copy link
Member Author

kitten commented Aug 21, 2022

Edit: We previously left this issue unlocked for quick feedback, but realised, it's likely better to lock it, for notices like the below 😅 Please open an issue if you find a regression or issue.

Patch Notes

We had a couple of reports of regressions, which have been addressed in the last few days over patch releases (Thanks for the reports!).
I'm listing them here just to provide a helpful update on what we've been tweaking, and what you can expect.

urql@3.0.1 / @urql/vue@1.0.1 / @urql/svelte@3.0.1 / @urql/preact@3.0.1

We found a small regression with GraphQL Code Generator, which showed that requiring variable types actually contained a small mistake.

What we failed to take into account was that multiple variables could be defined that will all be optional, which GCG then uses to mark the entire variables object as optional. We've fixed the typings to account for this.

@urql/vue@1.0.2

We discovered an issue that caused promise-based usage of the useQuery Vue function to fail, due to a small mistake in how we defined the immediate unsubscribe action when the Client returned a result.

Ultimately, this was caused because we stopped transpiling const/let to var, but we fixed the mistake in @urql/vie directly but also start transpiling const/let again to prevent this from happening proactively.

@urql/core@3.0.1

We previously changed how the Client applies the default request policy and passed in request policies, but didn't realise that useQuery in react-urql relies on the old behaviour and would hence cause requestPolicy to be set to undefined.

This has been fixed and we now correctly use defaults as passed to the Client or cache-first.

@urql-graphql urql-graphql locked and limited conversation to collaborators Aug 21, 2022
@kitten kitten unpinned this issue Dec 1, 2022
@kitten kitten closed this as completed Jan 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants