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

RFC: Reduce size of shipped GraphQL.js code by default #3096

Closed
kitten opened this issue Mar 24, 2023 · 1 comment · Fixed by #3097
Closed

RFC: Reduce size of shipped GraphQL.js code by default #3096

kitten opened this issue Mar 24, 2023 · 1 comment · Fixed by #3097
Labels
future 🔮 An enhancement or feature proposal that will be addressed after the next release

Comments

@kitten
Copy link
Member

kitten commented Mar 24, 2023

Summary

As it stands today, most apps ship at least 10kB gzip of JS code to include common utilities from graphql in their apps for @urql/core and all of urql’s dependencies include a peer dependency on graphql.

This is because @urql/core, and most of the client-side GraphQL ecosystem, depends on the following utilities in graphql to drive support of the query language and AST:

import { parse, print, visit, Kind, GraphQLError } from 'graphql';

Recently, we’ve experimented with bringing this size down with the graphql-web-lite project which is a “rebuilt” package of graphql that replaces the common utilities we use and is a full shim of graphql that can be aliased in for it. This brings the above size down from 10kB to ~3kB, a change of at least -7kB gzip.

Most of this change is driven by the @0no-co/graphql.web project, which reimplements the above utilities while maintaining the same performance and a 100% test coverage, while reimplementing the parts of graphql that @urql/core depends on.

If we shipped this by default, all currently deployed urql apps that were to upgrade immediately shrink in size. In fact, the base bundlesize impact of importing @urql/core would reduce to 10kB gzip in total, meaning, that while these seem like small reductions to some, we’d introduce an impact on bundlesize of over -50%.

We would have to maintain type compatibility and escape hatches nonetheless.

Proposed Solution

This change would impact all three of the aforementioned packages, plus all packages in the urql monorepo currently.

Changees in @urql/core

  • All imports in @urql/core must switch from graphql to @0no-co/graphql.web.
  • Its peerDependency on graphql is removed.
  • When it accepts a DocumentNode, DefinitionNode, or GraphQLError it must accept types that are either from graphql or from @0no-co/graphql.web in case of type incompatibilities
  • It must export an input type that accepts DocumentNode | TypedDocumentNode as per the above type aliases

Changes in @0no-co/graphql.web

  • It must replace its custom AST types with graphql’s AST types when graphql is installed
  • It must further mark graphql as an optional peer dependency
    • While TypeScript will crawl the node_modules separately, this may still be important, since a "deep" dependency like this must still somehow signal to a package manager that it may import a different dependency, i.e. it must be included somewhere for hoisting

Changes in graphql-web-lite

  • It must mark @0no-co/graphql.web as an external dependency, excluded from its bundle
    • This is so that graphql can still be aliased to graphql-web-lite to prevent code duplication

Outcome

All three changes together mean the following:

  • @urql/core will expose a type and accept a type of DocumentNode (& others) that can either come from the graphql package or the “internal” parser (i.e. @0no-co/graphql.web).
  • graphql will not be included anymore and all peer dependencies on it are removed.
  • graphql-web-lite can be aliased into an app, so the entire app makes use of the shared @0no-co/graphql.web, if so desired.
  • @0no-co/graphql.web can be aliased to graphql to switch back to the official package. (Considered a rare use-case)

This effectively provides type compatibility and reduces the risk of graphql still being used and installed in an app to a total of the usual 10kB penalty of including it, while maintaining type compatibility. This also provides intercompatibility with type generation tools that use graphql to type their outputs.

@kitten kitten added the future 🔮 An enhancement or feature proposal that will be addressed after the next release label Mar 24, 2023
@kitten
Copy link
Member Author

kitten commented Mar 24, 2023

The three PRs that implement the three changes laid out here are now all opened:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
future 🔮 An enhancement or feature proposal that will be addressed after the next release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant