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

[V3] Create @apollo/client/core bundle #5541

Merged
merged 13 commits into from
Nov 12, 2019
Merged
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
- The `gql` template tag should now be imported from the `@apollo/client` package, rather than the `graphql-tag` package. Although the `graphql-tag` package still works for now, future versions of `@apollo/client` may change the implementation details of `gql` without a major version bump. <br/>
[@hwillson](https://github.com/hwillson) in [#5451](https://github.com/apollographql/apollo-client/pull/5451)

- `@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)

### Breaking Changes

- Removed `graphql-anywhere` since it's no longer used by Apollo Client. <br/>
Expand Down Expand Up @@ -65,6 +68,8 @@
- The `ObservableQuery#getCurrentResult` method no longer falls back to reading from the cache, so calling it immediately after `client.watchQuery` will consistently return a `loading: true` result. When the `fetchPolicy` permits cached results, those results will be delivered via the `next` method of the `ObservableQuery`, and can be obtained by `getCurrentResult` after they have been delivered. This change prevents race conditions where the initial behavior of one query could depend on the timing of cache writes associated with other queries. </br>
[@benjamn](https://github.com/benjamn) in [#5565](https://github.com/apollographql/apollo-client/pull/5565)

- The `QueryOptions`, `MutationOptions`, and `SubscriptionOptions` React Apollo interfaces have been renamed to `QueryDataOptions`, `MutationDataOptions`, and `SubscriptionDataOptions` (to avoid conflicting with similarly named and exported Apollo Client interfaces).

## Apollo Client (2.6.4)

### Apollo Client (2.6.4)
Expand Down
73 changes: 62 additions & 11 deletions config/prepareDist.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
// The Apollo Client source that is published to npm is located in the
// "dist" directory. This utility script is called just before deploying
// Apollo Client, to make sure the "dist" directory is prepared for publishing.
// "dist" directory. This utility script is called when building Apollo Client,
// to make sure the "dist" directory is prepared for publishing.
//
// This script will:
//
// - Copy the current root package.json into "dist" after adjusting it for
// publishing.
// - Copy the supporting files from the root into "dist" (e.g. `README.MD`,
// `LICENSE`, etc.)
// `LICENSE`, etc.).
// - Create a new `package.json` for each sub-set bundle we support, and
// store it in the appropriate dist sub-directory.

const packageJson = require('../package.json');
const fs = require('fs');
const recast = require('recast');


/* @apollo/client */

const packageJson = require('../package.json');

// The root package.json is marked as private to prevent publishing
// from happening in the root of the project. This sets the package back to
Expand All @@ -25,13 +32,14 @@ delete packageJson.bundlesize;
// on-going package development (e.g. running tests, supporting npm link, etc.).
// When publishing from "dist" however, we need to update the package.json
// to point to the files within the same directory.
const distPackageJson = JSON.stringify(
packageJson,
(_key, value) => (
typeof value === 'string' ? value.replace(/\.\/dist\//, '') : value
),
2
);
const distPackageJson = JSON.stringify(packageJson, (_key, value) => {
if (typeof value === 'string' && value.startsWith('./dist/')) {
const parts = value.split('/');
parts.splice(1, 1); // remove dist
return parts.join('/');
hwillson marked this conversation as resolved.
Show resolved Hide resolved
}
return value;
}, 2) + "\n";

// Save the modified package.json to "dist"
fs.writeFileSync(`${__dirname}/../dist/package.json`, distPackageJson);
Expand All @@ -41,3 +49,46 @@ const srcDir = `${__dirname}/..`;
const destDir = `${srcDir}/dist`;
fs.copyFileSync(`${srcDir}/README.md`, `${destDir}/README.md`);
fs.copyFileSync(`${srcDir}/LICENSE`, `${destDir}/LICENSE`);


/* @apollo/client/core */

function buildPackageJson(bundleName) {
return JSON.stringify({
name: `@apollo/client/${bundleName}`,
main: `${bundleName}.cjs.js`,
benjamn marked this conversation as resolved.
Show resolved Hide resolved
module: 'index.js',
types: 'index.d.ts',
}, 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];",
hwillson marked this conversation as resolved.
Show resolved Hide resolved
"});",
"",
].join('\n'));
46 changes: 23 additions & 23 deletions config/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import packageJson from '../package.json';
const distDir = './dist';

const globals = {
'tslib': 'tslib',
tslib: 'tslib',
'ts-invariant': 'invariant',
'symbol-observable': '$$observable',
'graphql/language/printer': 'print',
Expand All @@ -21,7 +21,7 @@ const globals = {
'@wry/equality': 'wryEquality',
graphql: 'graphql',
react: 'React',
'zen-observable': 'Observable'
'zen-observable': 'Observable',
};

const hasOwn = Object.prototype.hasOwnProperty;
Expand All @@ -30,12 +30,12 @@ function external(id) {
return hasOwn.call(globals, id);
}

function prepareESM() {
function prepareESM(input, outputDir) {
return {
input: packageJson.module,
input,
external,
output: {
dir: distDir,
dir: outputDir,
format: 'esm',
sourcemap: true,
},
Expand All @@ -58,39 +58,39 @@ function prepareESM() {
}),
cjs({
namedExports: {
'graphql-tag': ['gql']
}
'graphql-tag': ['gql'],
},
}),
]
],
};
}

function prepareCJS() {
function prepareCJS(input, output) {
return {
input: packageJson.module,
input,
external,
output: {
file: packageJson.main,
file: output,
format: 'cjs',
sourcemap: true,
exports: 'named'
exports: 'named',
},
plugins: [
nodeResolve(),
cjs({
namedExports: {
'graphql-tag': ['gql']
}
'graphql-tag': ['gql'],
},
}),
]
}
],
};
}

function prepareCJSMinified() {
function prepareCJSMinified(input) {
return {
input: packageJson.main,
input,
output: {
file: packageJson.main.replace('.js', '.min.js'),
file: input.replace('.js', '.min.js'),
format: 'cjs',
},
plugins: [
Expand Down Expand Up @@ -141,10 +141,10 @@ function prepareTesting() {

function rollup() {
return [
prepareESM(),
prepareCJS(),
prepareCJSMinified(),
prepareTesting()
prepareESM(packageJson.module, distDir),
prepareCJS(packageJson.module, packageJson.main),
prepareCJSMinified(packageJson.main),
prepareTesting(),
];
}

Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"scripts": {
"prebuild": "npm run clean",
"build": "npx tsc",
"postbuild": "npm run bundle",
"postbuild": "npm run bundle && npm run prepdist",
"watch": "npx tsc-watch --onSuccess \"npm run postbuild\"",
"clean": "npx rimraf -r dist coverage lib",
"test": "jest --config ./config/jest.config.js",
Expand All @@ -41,7 +41,7 @@
"coverage:upload": "npx codecov",
"bundlesize": "npm run build && bundlesize",
"prepdist": "node ./config/prepareDist.js",
"predeploy": "npm run build && npm run prepdist",
"predeploy": "npm run build",
"deploy": "cd dist && npm publish --tag beta"
},
"bundlesize": [
Expand Down Expand Up @@ -89,6 +89,7 @@
"prop-types": "15.7.2",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"recast": "^0.18.5",
"rimraf": "^3.0.0",
"rollup": "1.21.2",
"rollup-plugin-commonjs": "^10.1.0",
Expand Down
85 changes: 85 additions & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* Core */

export {
ApolloClient,
ApolloClientOptions,
DefaultOptions
} from '../ApolloClient';
export {
ObservableQuery,
FetchMoreOptions,
UpdateQueryOptions,
ApolloCurrentQueryResult,
} from '../core/ObservableQuery';
export {
QueryBaseOptions,
QueryOptions,
WatchQueryOptions,
MutationOptions,
SubscriptionOptions,
FetchPolicy,
WatchQueryFetchPolicy,
ErrorPolicy,
FetchMoreQueryOptions,
SubscribeToMoreOptions,
MutationUpdaterFn,
} from '../core/watchQueryOptions';
export { NetworkStatus } from '../core/networkStatus';
export * from '../core/types';
export {
Resolver,
FragmentMatcher as LocalStateFragmentMatcher,
} from '../core/LocalState';
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';

/* Link */

export { empty } from '../link/core/empty';
export { from } from '../link/core/from';
export { split } from '../link/core/split';
export { concat } from '../link/core/concat';
export { execute } from '../link/core/execute';
export { ApolloLink } from '../link/core/ApolloLink';
export * from '../link/core/types';
export {
parseAndCheckHttpResponse,
ServerParseError
} from '../link/http/parseAndCheckHttpResponse';
export {
serializeFetchParameter,
ClientParseError
} from '../link/http/serializeFetchParameter';
export {
HttpOptions,
fallbackHttpConfig,
selectHttpOptionsAndBody,
UriFunction
} from '../link/http/selectHttpOptionsAndBody';
export { checkFetcher } from '../link/http/checkFetcher';
export { createSignalIfSupported } from '../link/http/createSignalIfSupported';
export { selectURI } from '../link/http/selectURI';
export { createHttpLink } from '../link/http/createHttpLink';
export { HttpLink } from '../link/http/HttpLink';
export { fromError } from '../link/utils/fromError';
export { ServerError, throwServerError } from '../link/utils/throwServerError';

/* Utilities */

export { Observable } from '../utilities/observables/Observable';
export { getMainDefinition } from '../utilities/graphql/getFromAST';

/* Supporting */

export { default as gql } from 'graphql-tag';
Loading