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

Merge React Apollo hooks into Apollo Client #5357

Merged
merged 29 commits into from
Sep 24, 2019
Merged

Conversation

hwillson
Copy link
Member

@hwillson hwillson commented Sep 23, 2019

This PR extracts and merges the React Apollo hooks code into the Apollo Client core, which means this is now possible:

import { ApolloClient, ApolloProvider, useQuery } from '@apollo/client';

When Apollo Client 3.0 launches, library users will no longer have to install separate packages to use React hooks with Apollo Client. Everything needed to combine Apollo Client with React to manage GraphQL based data will be available through one package, @apollo/client. Aside from making things easier for library consumers, these changes also set a future foundation for tighter integration between Apollo Client and its React integration. More involved changes that previously required updates to apollo-client and react-apollo separately can now be managed in one central location, which will help reduce bugs and speed up feature request additions that involve both projects.

Important notes about these changes are listed below.

1. React Apollo HOC/Component deprecation

We're following the React team's lead and are planning for a hooks only future. To this end, this PR only merges React Apollo's hooks into the AC core. RA's HOC and render proper components are not being moved over, and will continue to be housed under the @apollo/react-hoc and @apollo/react-components packages. Those paradigms will be updated behind the scenes to use the hooks from Apollo Client, but they will be maintained separately. When Apollo Client launches, React Apollo's HOC/Components will be officially deprecated (but will continue to receive bug fixes and other forms of support until sometime in 2020).

2. New bundling strategy

To help offset the increased bundle size these changes introduce, this PR includes a new bundling strategy to help modern build tooling better leverage tree-shaking / dead code elimination.

The current version of Apollo Client leverages a default CJS bundle (pointed to by the package.json main property), and an ESM bundle (pointed to by the package.json module property). While AC breaks all original ESM source out into ./lib and makes sure its accessible in the final package, the fact that the ESM bundle is being pointed to by module means that the original ESM code can't be leveraged properly for tree-shaking / DCE. Tools like webpack are only seeing the combined ESM bundle, which means it can't traverse the original code and more effectively remove unreachable elements.

This PR retains the package.json main CJS bundle approach (since having all code available on the server isn't as big of a deal), but no longer builds an ESM bundle. The package.json module property now points to ./lib/index.js, and we're relying on modern build tooling to tree-shake / DCE / bundle the AC source.

This PR also removes UMD bundle support. UMD use of this project has been quite low, and has never really been that effective due to the external dependencies Apollo Client requires.

3. React Apollo SSR stays separate (for now)

React Apollo's SSR package (@apollo/react-ssr) isn't being merged into Apollo Client, yet. For now anyone interested in using SSR with Apollo Client should still install the @apollo/react-ssr package directly. When React's suspense + data fetching approach finalizes (hopefully in the next couple of months), we'll be taking a closer look at AC's SSR approach as we work on our suspense integration.

4. React testing

This PR merges React Apollo's @apollo/react-testing code into the Apollo Client core, but it is not included by default in application bundles (since it's really only needed during development). To access React testing utilities from AC, direct cherry-pick imports can be used:

import { MockedProvider } from '@apollo/client/lib/react/testing';

This might change, but for now this is the approach outlined in this PR.

Falling back on the Jest default will work now that we're not
using a monorepo, and open things up to test further nested
`__tests__` directories (which will be needed to test React
changes).
React Apollo uses its own copy of `OperationVariables`; let's
update AC's version, so we can configure RA to use it after it has
been merged in.
This commit kicks of the initial merge of React Apollo into
Apollo Client. It merges in the source of:

- @apollo/react-common
- @apollo/react-hooks
- @apollo/react-testing

The HOC (@apollo/react-hoc) and components (@apollo/react-components)
packages are not going to be brought into Apollo Client, and
the React SSR package (@apollo/react-ssr) will also be kept separate
for now.

This commit represents the initial merge of the code (with changes
required to get all tests passing), but does not represent the
final state of Apollo Client's React integration. Now that the
RA code is part of AC, work on leveraging the tighter RA/AC
integration can proceed.
The TS rules are a bit more strict in this project (compared to
React Apollo).
New exemptions required by React Apollo
This is just a preliminary bump; this number will go down as we
start refactoring.
This, along with using `@testing-library/react`'s `wait` function,
 gets rid of all React "you must use act()" warnings.
These new rollup config elements will create a separate
`testing.js` CJS based bundle, that contains React testing
utilities like `MockedProvider`. Applications can access this
new bundle like:

import { MockedProvider } from '@apollo/client/lib/testing';
Apollo Client is already pulling a similar type from Apollo Link,
so this updates the React code to do the same.
Apollo Client use doesn't really benefit from having a UMD
bundle, since the project has external dependencies that aren't
bundled into the UMD.
These changes wire up a new Rollup based bundling approach. We
no longer build and provide an ESM bundle. By providing an ESM
bundle, and pointing to it via the `package.json` `module`
property, we were inadvertently reducing the effectiveness of
build tool tree shaking / dead code elimination capabilities.
For example, since webpack was getting the ESM bundle from the
`module` property, it wasn't able to get to the fully extracted
ESM source in `./lib`, to use it for DCE.

With the changes in this commit, the `package.json` continues
to point `main` to the CJS bundle (with all Apollo Client code
in it), and now points `module` to the non-bundled ESM entry
point of `./lib/index.js`. This means we're leaving the bundling
of ESM code up to Apollo Client consumers and their build tooling,
most of which will be able to leverage the expanded ESM source
to build more efficient bundles on their side.

We'll re-visit this strategy as work on AC 3 progresses, but so
far the results have been promising.
@benjamn updating to 0.11.2 introduced:

```
src/cache/inmemory/entityCache.ts:2:15 - error TS2305:
Module '"apollo-client/node_modules/optimism/lib"' has no exported
member 'OptimisticDependencyFunction'.
```
The source links needed to be updated to match the new non-monorepo
project structure. I'm not sure why the API is being excluded from
link checking, but it's defintiely needed. Links like
`/api/core/#ApolloClient.resetStore` aren't working, when they
should be. But since the API was being excluded previosuly,
this commit fixes the config to exclude it again.
@hwillson hwillson self-assigned this Sep 23, 2019
Copy link
Member

@benjamn benjamn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great to me!

config/rollup.config.js Show resolved Hide resolved
src/react/hooks/__tests__/useMutation.test.tsx Outdated Show resolved Hide resolved
docs/source/recipes/testing.mdx Outdated Show resolved Hide resolved
On the React Apollo side, it's only required when using
`@apollo/react-ssr`. Since we're not merging in the RA SSR code
yet, we don't need it as a peer dep.
`wait` already returns a promise so we can just return it.
Since we're publishing from within the "dist" directory, and
publishing is going to be blocked from the project root,
we don't need to maintain an .npmignore file.
These changes include a new script that is used to prepare the
"dist" directory for publishing. This includes:

- Copying a modified package.json into "dist", after it has been
  adjusted (remove "./dist" directory prefixes, remove un-needed
  package.json properties, and remove the private flag).
- Copying the README.md into "dist".

This script is now called as part of the "predeploy" script.
The "deploy" script will now also cd into "dist" before
publishing, so only the contents in "dist" will be published to
npm (and "dist" will essentially serve as the published package
root).
config/prepareDist.js Outdated Show resolved Hide resolved
@hwillson
Copy link
Member Author

We might change the approach introduced in 4c7af4e, but I'll merge this PR as is, and we'll continue the discussion / changes separately.

@hwillson hwillson merged commit 6f6aad8 into release-3.0 Sep 24, 2019
@hwillson hwillson deleted the hello-react-apollo branch September 24, 2019 15:08
@benjamn benjamn mentioned this pull request Sep 24, 2019
31 tasks
@jorroll
Copy link

jorroll commented Nov 16, 2019

@hwillson I'm surprised that no one has asked this yet, but how will this change affect those of us who use Apollo without using React (in my case, Angular)?

  • Will React now be a peer dependency of @apollo/client?
  • Will tree shaking now be (somewhat) required for non-react projects?

Addressing non-react usage (if still supported in some way) would be helpful.

Edit: For reference, I found my way here from the changelog

Edit 2: Oops! I jumpted the gun. Sorry! Farther down I see that there is a separate entry point for non-react usage

@apollo/client/core can be used to import the Apollo Client core, which includes everything the main @apollo/client package does, except for all React related functionality.

@hwillson
Copy link
Member Author

@thefliik If you don't want to use React or AC's React integration, you can import from @apollo/client/core instead of @apollo/client. E.g.:

import { ApolloClient } from '@apollo/client/core';

Using @apollo/client/core will give you access to all parts of AC excluding anything that touches (or requires) React.

This will definitely be better documented when we go live with AC 3.

@jorroll
Copy link

jorroll commented Nov 16, 2019

@hwillson makes sense. Thanks for the info!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants