Skip to content

Commit

Permalink
Merge pull request #5577 from apollographql/cache-entry-point
Browse files Browse the repository at this point in the history
Wire up the `@apollo/client/cache` entry point
  • Loading branch information
hwillson authored Nov 15, 2019
2 parents da508d7 + 6a5b636 commit 2098d1b
Show file tree
Hide file tree
Showing 20 changed files with 111 additions and 57 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
- `@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. <br/>
[@kamilkisiela](https://github.com/kamilkisiela) in [#5541](https://github.com/apollographql/apollo-client/pull/5541)

- `@apollo/client/cache` can be used to import the Apollo Client cache without importing other parts of the Apollo Client codebase. <br/>
[@hwillson](https://github.com/hwillson) in [#5577](https://github.com/apollographql/apollo-client/pull/5577)

### Breaking Changes

- Removed `graphql-anywhere` since it's no longer used by Apollo Client. <br/>
Expand Down
75 changes: 43 additions & 32 deletions config/prepareDist.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
const fs = require('fs');
const recast = require('recast');

const distRoot = `${__dirname}/../dist`;


/* @apollo/client */

Expand Down Expand Up @@ -42,7 +44,7 @@ const distPackageJson = JSON.stringify(packageJson, (_key, value) => {
}, 2) + "\n";

// Save the modified package.json to "dist"
fs.writeFileSync(`${__dirname}/../dist/package.json`, distPackageJson);
fs.writeFileSync(`${distRoot}/package.json`, distPackageJson);

// Copy supporting files into "dist"
const srcDir = `${__dirname}/..`;
Expand All @@ -51,7 +53,7 @@ fs.copyFileSync(`${srcDir}/README.md`, `${destDir}/README.md`);
fs.copyFileSync(`${srcDir}/LICENSE`, `${destDir}/LICENSE`);


/* @apollo/client/core */
/* @apollo/client/core, @apollo/client/cache */

function buildPackageJson(bundleName) {
return JSON.stringify({
Expand All @@ -62,33 +64,42 @@ function buildPackageJson(bundleName) {
}, null, 2) + "\n";
}

// Create a `core` bundle package.json, storing it in the dist core
// directory. This helps provide a way for Apollo Client to be used without
// React, via `@apollo/client/core`.
fs.writeFileSync(
`${__dirname}/../dist/core/package.json`,
buildPackageJson('core')
);

// Build a new `core.cjs.js` entry point file, that includes everything
// except the exports listed in `src/react/index.ts`. Copy this file into
// the `dist/core` directory, to allow Apollo Client core only imports
// using `@apollo/client/core`.

const reactIndexSrc = fs.readFileSync(`${__dirname}/../dist/react/index.js`);
const reactExports = [];
recast.visit(recast.parse(reactIndexSrc), {
visitExportSpecifier(path) {
reactExports.push(path.value.exported.name);
return false;
},
});

fs.writeFileSync(`${__dirname}/../dist/core/core.cjs.js`, [
"const allExports = require('../apollo-client.cjs');",
`const reactExportNames = new Set(${JSON.stringify(reactExports)});`,
"Object.keys(allExports).forEach(name => {",
" if (!reactExportNames.has(name)) exports[name] = allExports[name];",
"});",
"",
].join('\n'));
function loadExportNames(bundleName) {
const indexSrc =
fs.readFileSync(`${distRoot}/${bundleName}/index.js`);
const exportNames = [];
recast.visit(recast.parse(indexSrc), {
visitExportSpecifier(path) {
exportNames.push(path.value.exported.name);
return false;
},
});
return exportNames;
}

function writeCjsIndex(bundleName, exportNames, includeNames = true) {
const filterPrefix = includeNames ? '' : '!';
fs.writeFileSync(`${distRoot}/${bundleName}/${bundleName}.cjs.js`, [
"const allExports = require('../apollo-client.cjs');",
`const names = new Set(${JSON.stringify(exportNames)});`,
"Object.keys(allExports).forEach(name => {",
` if (${filterPrefix}names.has(name)) {`,
" exports[name] = allExports[name];",
" }",
"});",
"",
].join('\n'));
}

// Create `core` and `cache` bundle package.json files, storing them in their
// associated dist directory. This helps provide a way for the Apollo Client
// core to be used without React (via `@apollo/client/core`), and the cache
// to be used by itself (via `@apollo/client/cache`). Also create
// `core.cjs.js` and `cache.cjs.js` CommonJS entry point files that only
// include the exports needed for each bundle.

fs.writeFileSync(`${distRoot}/core/package.json`, buildPackageJson('core'));
writeCjsIndex('core', loadExportNames('react'), false);

fs.writeFileSync(`${distRoot}/cache/package.json`, buildPackageJson('cache'));
writeCjsIndex('cache', loadExportNames('cache'));
10 changes: 10 additions & 0 deletions src/cache/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export { Transaction, ApolloCache } from './core/cache';
export { Cache } from './core/types/Cache';
export { DataProxy } from './core/types/DataProxy';

export {
InMemoryCache,
InMemoryCacheConfig,
} from './inmemory/inMemoryCache';
export { defaultDataIdFromObject } from './inmemory/policies';
export * from './inmemory/types';
10 changes: 1 addition & 9 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,7 @@ export { isApolloError, ApolloError } from '../errors/ApolloError';

/* Cache */

export { Transaction, ApolloCache } from '../cache/core/cache';
export { Cache } from '../cache/core/types/Cache';
export { DataProxy } from '../cache/core/types/DataProxy';
export {
InMemoryCache,
InMemoryCacheConfig,
} from '../cache/inmemory/inMemoryCache';
export { defaultDataIdFromObject } from '../cache/inmemory/policies';
export * from '../cache/inmemory/types';
export * from '../cache';

/* Link */

Expand Down
3 changes: 2 additions & 1 deletion src/react/context/ApolloConsumer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react';
import { invariant } from 'ts-invariant';

import { ApolloClient } from '../../ApolloClient';
import { getApolloContext } from './ApolloContext';
import { requireReactLazily } from '../react';

export interface ApolloConsumerProps {
children: (client: ApolloClient<object>) => React.ReactChild | null;
}

export const ApolloConsumer: React.FC<ApolloConsumerProps> = props => {
const React = requireReactLazily();
const ApolloContext = getApolloContext();
return (
<ApolloContext.Consumer>
Expand Down
5 changes: 3 additions & 2 deletions src/react/context/ApolloContext.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';

import { ApolloClient } from '../../ApolloClient';
import { requireReactLazily } from '../react';

export interface ApolloContextValue {
client?: ApolloClient<object>;
Expand All @@ -17,6 +16,7 @@ export interface ApolloContextValue {
const contextSymbol = Symbol.for('__APOLLO_CONTEXT__');

export function resetApolloContext() {
const React = requireReactLazily();
Object.defineProperty(React, contextSymbol, {
value: React.createContext<ApolloContextValue>({}),
enumerable: false,
Expand All @@ -26,6 +26,7 @@ export function resetApolloContext() {
}

export function getApolloContext() {
const React = requireReactLazily();
if (!(React as any)[contextSymbol]) {
resetApolloContext();
}
Expand Down
3 changes: 2 additions & 1 deletion src/react/context/ApolloProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { invariant } from 'ts-invariant';

import { ApolloClient } from '../../ApolloClient';
import { getApolloContext } from './ApolloContext';
import { requireReactLazily } from '../react';

export interface ApolloProviderProps<TCache> {
client: ApolloClient<TCache>;
Expand All @@ -13,6 +13,7 @@ export const ApolloProvider: React.FC<ApolloProviderProps<any>> = ({
client,
children
}) => {
const React = requireReactLazily();
const ApolloContext = getApolloContext();
return (
<ApolloContext.Consumer>
Expand Down
4 changes: 3 additions & 1 deletion src/react/context/__tests__/ApolloConsumer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { render, cleanup } from '@testing-library/react';

import { ApolloLink } from '../../../link/core/ApolloLink';
Expand All @@ -7,6 +6,9 @@ import { InMemoryCache as Cache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../ApolloProvider';
import { ApolloConsumer } from '../ApolloConsumer';
import { getApolloContext } from '../ApolloContext';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();

const client = new ApolloClient({
cache: new Cache(),
Expand Down
5 changes: 4 additions & 1 deletion src/react/context/__tests__/ApolloProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React, { useContext } from 'react';
import { render, cleanup } from '@testing-library/react';

import { ApolloLink } from '../../../link/core/ApolloLink';
import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache as Cache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../ApolloProvider';
import { getApolloContext } from '../ApolloContext';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();
const { useContext } = React;

describe('<ApolloProvider /> Component', () => {
afterEach(cleanup);
Expand Down
4 changes: 3 additions & 1 deletion src/react/hooks/__tests__/useApolloClient.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { render, cleanup } from '@testing-library/react';
import { InvariantError } from 'ts-invariant';

Expand All @@ -8,6 +7,9 @@ import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache } from '../../../cache/inmemory/inMemoryCache';
import { useApolloClient } from '../useApolloClient';
import { resetApolloContext } from '../../context/ApolloContext';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();

describe('useApolloClient Hook', () => {
afterEach(() => {
Expand Down
4 changes: 3 additions & 1 deletion src/react/hooks/__tests__/useLazyQuery.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { DocumentNode } from 'graphql';
import gql from 'graphql-tag';
import { render, wait } from '@testing-library/react';
Expand All @@ -8,6 +7,9 @@ import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../../context/ApolloProvider';
import { useLazyQuery } from '../useLazyQuery';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();

describe('useLazyQuery Hook', () => {
const CAR_QUERY: DocumentNode = gql`
Expand Down
5 changes: 4 additions & 1 deletion src/react/hooks/__tests__/useMutation.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React, { useEffect } from 'react';
import { DocumentNode } from 'graphql';
import gql from 'graphql-tag';
import { render, cleanup, wait } from '@testing-library/react';
Expand All @@ -9,6 +8,10 @@ import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../../context/ApolloProvider';
import { useMutation } from '../useMutation';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();
const { useEffect } = React;

describe('useMutation Hook', () => {
interface Todo {
Expand Down
5 changes: 4 additions & 1 deletion src/react/hooks/__tests__/useQuery.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React, { useState, useReducer } from 'react';
import { DocumentNode, GraphQLError } from 'graphql';
import gql from 'graphql-tag';
import { render, cleanup, wait } from '@testing-library/react';
Expand All @@ -12,6 +11,10 @@ import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../../context/ApolloProvider';
import { useQuery } from '../useQuery';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();
const { useState, useReducer } = React;

describe('useQuery Hook', () => {
const CAR_QUERY: DocumentNode = gql`
Expand Down
4 changes: 3 additions & 1 deletion src/react/hooks/__tests__/useSubscription.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { render, cleanup, wait } from '@testing-library/react';
import gql from 'graphql-tag';

Expand All @@ -7,6 +6,9 @@ import { ApolloClient } from '../../../ApolloClient';
import { InMemoryCache as Cache } from '../../../cache/inmemory/inMemoryCache';
import { ApolloProvider } from '../../context/ApolloProvider';
import { useSubscription } from '../useSubscription';
import { requireReactLazily } from '../../react';

const React = requireReactLazily();

describe('useSubscription Hook', () => {
afterEach(cleanup);
Expand Down
3 changes: 2 additions & 1 deletion src/react/hooks/useApolloClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { invariant } from 'ts-invariant';

import { ApolloClient } from '../../ApolloClient';
import { getApolloContext } from '../context/ApolloContext';
import { requireReactLazily } from '../react';

export function useApolloClient(): ApolloClient<object> {
const React = requireReactLazily();
const { client } = React.useContext(getApolloContext());
invariant(
client,
Expand Down
3 changes: 2 additions & 1 deletion src/react/hooks/useMutation.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { useContext, useState, useRef, useEffect } from 'react';
import { DocumentNode } from 'graphql';

import { MutationHookOptions, MutationTuple } from '../types/types';
import { MutationData } from '../data/MutationData';
import { OperationVariables } from '../../core/types';
import { getApolloContext } from '../context/ApolloContext';
import { requireReactLazily } from '../react';

export function useMutation<TData = any, TVariables = OperationVariables>(
mutation: DocumentNode,
options?: MutationHookOptions<TData, TVariables>
): MutationTuple<TData, TVariables> {
const { useContext, useState, useRef, useEffect } = requireReactLazily();
const context = useContext(getApolloContext());
const [result, setResult] = useState({ called: false, loading: false });
const updatedOptions = options ? { ...options, mutation } : { mutation };
Expand Down
4 changes: 3 additions & 1 deletion src/react/hooks/useSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useContext, useState, useRef, useEffect } from 'react';
import { DocumentNode } from 'graphql';

import { SubscriptionHookOptions } from '../types/types';
import { SubscriptionData } from '../data/SubscriptionData';
import { OperationVariables } from '../../core/types';
import { getApolloContext } from '../context/ApolloContext';
import { requireReactLazily } from '../react';

export function useSubscription<TData = any, TVariables = OperationVariables>(
subscription: DocumentNode,
options?: SubscriptionHookOptions<TData, TVariables>
) {
const React = requireReactLazily();
const { useContext, useState, useRef, useEffect } = React;
const context = useContext(getApolloContext());
const updatedOptions = options
? { ...options, subscription }
Expand Down
4 changes: 3 additions & 1 deletion src/react/hooks/utils/useBaseQuery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useContext, useEffect, useReducer, useRef } from 'react';
import { DocumentNode } from 'graphql';

import {
Expand All @@ -11,12 +10,15 @@ import { QueryData } from '../../data/QueryData';
import { useDeepMemo } from './useDeepMemo';
import { OperationVariables } from '../../../core/types';
import { getApolloContext } from '../../context/ApolloContext';
import { requireReactLazily } from '../../react';

export function useBaseQuery<TData = any, TVariables = OperationVariables>(
query: DocumentNode,
options?: QueryHookOptions<TData, TVariables>,
lazy = false
) {
const React = requireReactLazily();
const { useContext, useEffect, useReducer, useRef } = React;
const context = useContext(getApolloContext());
const [tick, forceUpdate] = useReducer(x => x + 1, 0);
const updatedOptions = options ? { ...options, query } : { query };
Expand Down
5 changes: 4 additions & 1 deletion src/react/hooks/utils/useDeepMemo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useRef } from 'react';
import { equal as isEqual } from '@wry/equality';

import { requireReactLazily } from '../../react';

/**
* Memoize a result using deep equality. This hook has two advantages over
* React.useMemo: it uses deep equality to compare memo keys, and it guarantees
Expand All @@ -12,6 +13,8 @@ export function useDeepMemo<TKey, TValue>(
memoFn: () => TValue,
key: TKey
): TValue {
const React = requireReactLazily();
const { useRef } = React;
const ref = useRef<{ key: TKey; value: TValue }>();

if (!ref.current || !isEqual(key, ref.current.key)) {
Expand Down
Loading

0 comments on commit 2098d1b

Please sign in to comment.