profile
viewpoint
Ben Newman benjamn Meteor/Apollo (formerly: Facebook/Instagram, Quora, Mozilla) New York City http://twitter.com/benjamn

benjamn/ast-types 651

Esprima-compatible implementation of the Mozilla JS Parser API

amasad/debugjs 176

[Experimental] Lightweight JavaScript VM and stepping debugger in JavaScript

benjamn/arson 151

Efficient encoder and decoder for arbitrary objects

amasad/debugjs.com 94

Debug your JavaScript in the browser

benjamn/ast-path 4

Library for traversing syntax trees with easy access to an unbroken chain of parent references

benjamn/brigade 4

Bucket brigade for bundling browser modules

benjamn/cls 3

Class factory featuring inheritance of static properties, static constructors, lazy population of prototypes, and this._super

benjamn/arduino-wearables 2

A collection of code powering wearable Arduino projects

benjamn/apollo-server 1

GraphQL server for Express, Connect, HAPI and Koa, written in TypeScript

benjamn/babel-plugin-jscript 1

Babel plugin to fix buggy JScript named function expressions.

issue commentapollographql/apollo-client

Destructuring with defaults breaks due to conversion of `undefined` -> `null`

It's fine to experiment with deviations from the GraphQL specification to see what works, but you really need to be working with the latest code (@apollo/client, not apollo-client) if you want us to consider any changes to accommodate nonstandard usage.

I would also encourage you to find independent reasons why those changes should be made, so we can skip the whole discussion of whether your likes and dislikes regarding the GraphQL spec are worth entertaining.

and also fails to distinguish between a property with an undefined value and an object which does not have a property defined at all. These are two different states in javascript.

The null and undefined values are also different! You're assuming you can just replace any null you get with undefined, without knowing whether that means an undefined value or the absence of a value. How is that safe, exactly?

justinmchase

comment created time in a day

created tagapollographql/apollo-client

tagv3.0.0-beta.37

:rocket: A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server

created time in a day

push eventapollographql/apollo-client

Ben Newman

commit sha a38a2cad22910ef876ccbd189a1368b1dde999a4

Bump @apollo/client npm version to 3.0.0-beta.37.

view details

push time in a day

push eventapollographql/apollo-client

Ben Newman

commit sha 42878cb013a358eecaa7bbbdc568af2eb0f8cb58

Stop using proxy objects for InMemoryCache transactions. This essentially undoes #5484, so that reactive variables (which have access to the InMemoryCache object but know nothing about proxy objects) can benefit from transactional broadcast batching when calling cache.broadcastWatches().

view details

Ben Newman

commit sha 286c10ad7d1a8799c9d20c91af3500703cda245a

Rename InMemoryCache#makeLocalVar to makeVar. Shorter, and not as suggestive of Apollo Client 2.x local state. Returns a function of type ReactiveVar<T> (f.k.a. LocalVar<T>). Follow-up to #5799.

view details

Ben Newman

commit sha 80d1fade550b1aa08c0ebc2fe004102b3e9bf100

Make ReactiveVar updates trigger cache.broadcastWatches(). The broadcast is always synchronous, but you can group multiple variable updates together (with just one broadcast) using cache.performTransaction.

view details

Ben Newman

commit sha 03f00a1eb9fb1ccaad9119029eb270553a15b14c

Merge pull request #5976 from apollographql/reactive-cache.makeVar-broadcast Make updating cache.makeVar variables broadcast watches.

view details

push time in a day

delete branch apollographql/apollo-client

delete branch : reactive-cache.makeVar-broadcast

delete time in a day

PR merged apollographql/apollo-client

Make updating cache.makeVar variables broadcast watches. 🧞‍♂️ enhancement

This PR makes two user-visible changes:

  • The cache.makeLocalVar API introduced in #5799 has been renamed to cache.makeVar, for brevity and to avoid direct association with Apollo Client 2.x local state. Reactive variables should replace most use cases for local state, but they have many other potential uses. The type of the returned variable is now ReactiveVar<T> instead of LocalVar<T>.
  • Updating a reactive variable with a new value will now trigger a call to cache.broadcastWatches(). Because the ApolloCache API is mostly synchronous, this broadcast is also synchronous, but it's possible to batch multiple variable updates together by performing them within a cache.performTransaction block.

These changes are vital for making reactive variables truly reactive, but we still have some work to do to make sure broadcasting watched query data from the cache reliably pushes the new data into the view layer.

+46 -42

0 comment

5 changed files

benjamn

pr closed time in a day

PR opened apollographql/apollo-client

Reviewers
Make updating cache.makeVar variables broadcast watches. 🧞‍♂️ enhancement

This PR makes two user-visible changes:

  • The cache.makeLocalVar API introduced in #5799 has been renamed to cache.makeVar, for brevity and to avoid direct association with Apollo Client 2.x local state. Reactive variables should replace most use cases for local state, but they have many other potential uses. The type of the returned variable is now ReactiveVar<T> instead of LocalVar<T>.
  • Updating a reactive variable with a new value will now trigger a call to cache.broadcastWatches(). Because the ApolloCache API is mostly synchronous, this broadcast is also synchronous, but it's possible to batch multiple variable updates together by performing them within a cache.performTransaction block.

These changes are vital for making reactive variables truly reactive, but we still have some work to do to make sure broadcasting watched query data from the cache reliably pushes the new data into the view layer.

+46 -42

0 comment

5 changed files

pr created time in a day

delete branch apollographql/apollo-client

delete branch : eliminate-assign-utility

delete time in a day

push eventapollographql/apollo-client

Ben Newman

commit sha af2c69cfa5833123e072d0c15f9ed39be4660f4f

Eliminate needless custom assign utility. (#5973) Not only do we have the __assign helper from tslib to handle { ...object, ...spread } syntax, and folks can easily polyfill Object.assign in older browsers, but we were using this assign helper in only one place, and we didn't really need it there. Saves 78 bytes of bundle size (minified + gzip), which is pretty good for such an easy change.

view details

push time in a day

PR merged apollographql/apollo-client

Eliminate needless custom assign utility. 📦 bundle size 🔠 quick-and-easy 🧩 implementation-detail

Not only do we have the __assign helper from tslib to handle { ...object, ...spread } syntax, and folks can easily polyfill Object.assign in older browsers, but we were using this assign helper in only one place, and we didn't really need it there.

Saves 78 bytes of bundle size (minified + gzip), which is pretty good for such an easy change.

+13 -103

1 comment

3 changed files

benjamn

pr closed time in a day

push eventapollographql/apollo-client

Simon Bays

commit sha 003e0be6a803261f9841b16909f3e03046d48d56

Update link to docs for networkStatus Link was using an old url structure

view details

Simon Bays

commit sha 1d6cafd16d1db3e6f0977abd399fbfe7c81539a3

Merge branch 'master' into patch-1

view details

Stephen Barlow

commit sha 1d6593f440c10bba5a241ddb6b42f9e9ebb266e6

Merge branch 'master' into patch-1

view details

Stephen Barlow

commit sha 71c816a21ec383b3dfe8a22fdfcda2964474ddf1

Merge pull request #5875 from sbays/patch-1 Update link to docs for networkStatus

view details

Justin Waite

commit sha d42c2806a5e29fb09af933c6b8f401a59a4ea9b9

Add default implementation of ApolloCache#gc (#5974) * Add default implementation of ApolloCache#gc Addresses #5966 * Changelog update Co-authored-by: Hugh Willson <hugh@octonary.com>

view details

Ben Newman

commit sha 1b890d898e93da0b21d52b6aceea017ae917aa4e

Merge branch 'master' into eliminate-assign-utility

view details

push time in a day

issue commentmeteor/meteor

Creating or updating file issue isopacket `combined`

The relevant part of that stack trace is this:

sourcemapConsumer.destroy is not a function

That should be fixed by #10874, which is available in the Meteor 1.10 betas:

meteor update --release 1.10-beta.7

At this point, Meteor 1.10 is not much different from 1.9.2, so you might want to give the betas a try? Remember to commit your app to version control first, so that you can easily roll back if you encounter any instability.

iBeACoder

comment created time in a day

push eventmeteor/meteor

Ben Newman

commit sha 67671dc9b35c6728b9d7c65acee0acf812b6e98c

Bump package versions for 1.10-beta.7 release.

view details

push time in 2 days

Pull request review commentapollographql/apollo-client

Eliminate needless custom assign utility.

-/**- * Adds the properties of one or more source objects to a target object. Works exactly like- * `Object.assign`, but as a utility to maintain support for IE 11.- *- * @see https://github.com/apollostack/apollo-client/pull/1009- */-export function assign<A, B>(a: A, b: B): A & B;-export function assign<A, B, C>(a: A, b: B, c: C): A & B & C;-export function assign<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;-export function assign<A, B, C, D, E>(-  a: A,-  b: B,-  c: C,-  d: D,-  e: E,-): A & B & C & D & E;-export function assign(target: any, ...sources: Array<any>): any;-export function assign(-  target: { [key: string]: any },-  ...sources: Array<{ [key: string]: any }>-): { [key: string]: any } {-  sources.forEach(source => {-    if (typeof source === 'undefined' || source === null) {-      return;-    }-    Object.keys(source).forEach(key => {

This wasn't even correct, because Object.assign is specified to copy own Symbols as well as own keys.

benjamn

comment created time in 2 days

PR opened apollographql/apollo-client

Reviewers
Eliminate needless custom assign utility. 📦 bundle size 🔠 quick-and-easy 🧩 implementation-detail

Not only do we have the __assign helper from tslib to handle { ...object, ...spread } syntax, and folks can easily polyfill Object.assign in older browsers, but we were only using this assign helper in one place, and we didn't really need it there.

Saves 78 bytes of bundle size (minified + gzip), which is pretty good for such an easy change.

+13 -103

0 comment

3 changed files

pr created time in 2 days

create barnchapollographql/apollo-client

branch : eliminate-assign-utility

created branch time in 2 days

pull request commentfacebook/regenerator

add `.js` extension to file import

I don't think that regenerator works inside native ES modules

Why would that be, besides it not being necessary (because all JS environments with ESM support also have generator support)?

JLHwung

comment created time in 2 days

created tagmeteor/meteor

tagrelease/METEOR@1.10-beta.7

Meteor, the JavaScript App Platform

created time in 2 days

push eventfacebook/regenerator

Nicolò Ribaudo

commit sha 491714f6aac228397bd845a83faf18dda966e366

Pass Promise as a parameter to regeneratorRuntime.async() (#383) This makes it possible to run @babel/plugin-transform-runtime on regenerator's output to provide a Promise polyfill in old browsers.

view details

push time in 2 days

PR merged facebook/regenerator

Pass Promise as a parameter to regeneratorRuntime.async() CLA Signed

This makes it possible to run @babel/plugin-transform-runtime and @babel/preset-env's useBuiltIns on regenerator's output to provide a Promise polyfill in old browsers.

Fixes babel/babel#10678, babel/babel#10830

+178 -8

2 comments

4 changed files

nicolo-ribaudo

pr closed time in 2 days

push eventmeteor/meteor

filipenevola

commit sha 0132191dcd50c0d8923c68557c0222670f3bd09f

Bump Node version to 12.16.1

view details

filipenevola

commit sha 0c7c2a67310227cdb34e88efaadc382977d5261d

Bump $BUNDLE_VERSION to 12.16.1.0 before rebuilding dev bundle.

view details

Ben Newman

commit sha 0743289ff3993f32a6cb1bbcbb39fb6b6aea2a20

Add History.md section for Meteor 1.9.2.

view details

Ben Newman

commit sha 9c852da69599c35e3cf66c5ebed0eabe66bba2ab

Make optimisticLookupPackageJson return array of package.json objects. Commit 646fa4e3ee6baea585766807bc930123ba4d03f7 fixed #10547 by restricting optimisticLookupPackageJson to package.json files with a "name" property, which effectively skipped over intermediate package.json files with additional properties. However, in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick (see packages/modules-runtime/server.js), because ESM modules cannot be imported using require. For example, recent versions of the @babel/runtime package have a @babel/runtime/helpers/esm/package.json file for the ESM versions of its helpers (which specifies "type": "module"), but that package.json file does not have a "name" property, because it is not the root package.json file representing the entire @babel/runtime package. I considered making the "name" restriction configurable, but that would have fragmented the caching of optimisticLookupPackageJson. Instead, I made it return an array of all potentially relevant package.json objects, which can be safely cached. This means that the caller has to iterate over the array, but there is only one call site for this function (in tools/isobuild/package-source.js) right now, so that wasn't too much work.

view details

Ben Newman

commit sha 924c748ecc2d33ee1cddb2af00ecfb5286cf09a8

Avoid bailing out with module.useNode() for ESM modules. On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode() (see packages/modules-runtime/server.js). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works). To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. The good news is that ESM modules don't have access to nearly as many Node.js-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS. If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM using dynamic import(). For now, making sure we avoid bailing out for ESM code like @babel/runtime/helpers/esm/* is the priority.

view details

filipenevola

commit sha dad91bd581822a3e30a66b2cd0cf0b09d50b6b53

Bump package versions for 1.9.2-rc.0 release

view details

Ben Newman

commit sha c81738fbb3af8d38bd8a7c294a750f1697db9ffc

Update meteor-babel to version 7.8.2 and typescript to 3.7.5.

view details

Ben Newman

commit sha ec60e66ef9147ad4d9f8244c8cd27ecd4d610c50

Bump $BUNDLE_VERSION to 12.16.1.1 before rebuilding dev bundle.

view details

Ben Newman

commit sha 60355ae0e308d79dc2ae8a6fd8e6ab8e8d6d3b5e

Bump package versions for 1.9.2-rc.1 release.

view details

filipenevola

commit sha 05e7b81c2a2e166a9a17304b119ef4d57a0f2f4c

Bump package versions for 1.9.2 release

view details

filipenevola

commit sha b96fe01ffa1530b2c07867f942823ab4e3d12111

Updates 1.9.2 release date 2020-02-20

view details

Ben Newman

commit sha 34f88077094f575ebf02bfd6ae06157f372c569a

Merge pull request #10927 from meteor/release-1.9.2 Release 1.9.2

view details

Ben Newman

commit sha 150d387b44d81370d8c30d1bf0b4ff7e3f8c4c43

Merge branch 'master' into devel

view details

Ben Newman

commit sha f685b8c10db6b99e35ee6698be2a9a9fdb970d00

Bump $BUNDLE_VERSION to 12.16.1.2 before rebuilding dev bundle. Since Meteor 1.9.2 included a rebuilt dev bundle, it's important to rebuild the dev bundle again after merging master (which now corresponds to 1.9.2) into devel (which has seen a number of dev bundle-relevant changes that are not yet on master, e.g. MongoDB 4.0.6 => 4.2.1).

view details

Ben Newman

commit sha de5db52f87a69afadffb649127489d585eb6c08f

Merge branch 'devel' into release-1.10

view details

push time in 2 days

push eventmeteor/meteor

filipenevola

commit sha 0132191dcd50c0d8923c68557c0222670f3bd09f

Bump Node version to 12.16.1

view details

filipenevola

commit sha 0c7c2a67310227cdb34e88efaadc382977d5261d

Bump $BUNDLE_VERSION to 12.16.1.0 before rebuilding dev bundle.

view details

Ben Newman

commit sha 0743289ff3993f32a6cb1bbcbb39fb6b6aea2a20

Add History.md section for Meteor 1.9.2.

view details

Ben Newman

commit sha 9c852da69599c35e3cf66c5ebed0eabe66bba2ab

Make optimisticLookupPackageJson return array of package.json objects. Commit 646fa4e3ee6baea585766807bc930123ba4d03f7 fixed #10547 by restricting optimisticLookupPackageJson to package.json files with a "name" property, which effectively skipped over intermediate package.json files with additional properties. However, in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick (see packages/modules-runtime/server.js), because ESM modules cannot be imported using require. For example, recent versions of the @babel/runtime package have a @babel/runtime/helpers/esm/package.json file for the ESM versions of its helpers (which specifies "type": "module"), but that package.json file does not have a "name" property, because it is not the root package.json file representing the entire @babel/runtime package. I considered making the "name" restriction configurable, but that would have fragmented the caching of optimisticLookupPackageJson. Instead, I made it return an array of all potentially relevant package.json objects, which can be safely cached. This means that the caller has to iterate over the array, but there is only one call site for this function (in tools/isobuild/package-source.js) right now, so that wasn't too much work.

view details

Ben Newman

commit sha 924c748ecc2d33ee1cddb2af00ecfb5286cf09a8

Avoid bailing out with module.useNode() for ESM modules. On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode() (see packages/modules-runtime/server.js). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works). To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. The good news is that ESM modules don't have access to nearly as many Node.js-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS. If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM using dynamic import(). For now, making sure we avoid bailing out for ESM code like @babel/runtime/helpers/esm/* is the priority.

view details

filipenevola

commit sha dad91bd581822a3e30a66b2cd0cf0b09d50b6b53

Bump package versions for 1.9.2-rc.0 release

view details

Ben Newman

commit sha c81738fbb3af8d38bd8a7c294a750f1697db9ffc

Update meteor-babel to version 7.8.2 and typescript to 3.7.5.

view details

Ben Newman

commit sha ec60e66ef9147ad4d9f8244c8cd27ecd4d610c50

Bump $BUNDLE_VERSION to 12.16.1.1 before rebuilding dev bundle.

view details

Ben Newman

commit sha 60355ae0e308d79dc2ae8a6fd8e6ab8e8d6d3b5e

Bump package versions for 1.9.2-rc.1 release.

view details

filipenevola

commit sha 05e7b81c2a2e166a9a17304b119ef4d57a0f2f4c

Bump package versions for 1.9.2 release

view details

filipenevola

commit sha b96fe01ffa1530b2c07867f942823ab4e3d12111

Updates 1.9.2 release date 2020-02-20

view details

Ben Newman

commit sha 34f88077094f575ebf02bfd6ae06157f372c569a

Merge pull request #10927 from meteor/release-1.9.2 Release 1.9.2

view details

Ben Newman

commit sha 150d387b44d81370d8c30d1bf0b4ff7e3f8c4c43

Merge branch 'master' into devel

view details

Ben Newman

commit sha f685b8c10db6b99e35ee6698be2a9a9fdb970d00

Bump $BUNDLE_VERSION to 12.16.1.2 before rebuilding dev bundle. Since Meteor 1.9.2 included a rebuilt dev bundle, it's important to rebuild the dev bundle again after merging master (which now corresponds to 1.9.2) into devel (which has seen a number of dev bundle-relevant changes that are not yet on master, e.g. MongoDB 4.0.6 => 4.2.1).

view details

push time in 2 days

delete branch apollographql/apollo-client

delete branch : persistent-options.toReference

delete time in 2 days

push eventapollographql/apollo-client

Ben Newman

commit sha 3936a4fa9214ae2c99043b4db92e0f1466062f82

Reimplement legacy context.getCacheKey using cache.identify.

view details

Ben Newman

commit sha a877d4b0d0a7a2c09a3ceb83c637d65e57b206bc

Support toReference(obj, true) to persist obj into store. The options.toReference helper function is provided to custom read and merge functions, as well as to cache.modify modifier functions, via their details parameter (see #5909). See the tests included in this commit for examples of all three usages. The original purpose of toReference was to return a Reference object, { __ref: <ID> }, given an object with a __typename and the necessary key fields for that type. If these expectations are not met, toReference(obj) can return null, to indicate that the object could not be identified. Another toReference failure mode (besides returning null) is returning a Reference object that doesn't actually refer to anything stored in the cache. While this case is handled gracefully while reading from the cache (the non-existent object simply appears empty), you may have encountered cases where you _do_ want to persist the object that was passed to toReference into the cache, such as when a custom read function knows how to provide a perfectly adequate default object based on options.args. For those use cases, you can now call toReference(object, true) to merge the fields of the object into the cache, assuming it could be identified. The fields of the object are merged into the cache as-is, without any transformations to handle field arguments, aliases, directives, or variables. For those cases, cache.writeQuery or cache.writeFragment are still the best options. Also, toReference is not exposed outside of read/merge/modify functions, so if you're not in one of those functions you will have to call the normal writeQuery or writeFragment methods. Implementation-wise, since toReference may now need to call store.merge, it was most convenient to move the definition of the toReference method from the Policies class to the EntityStore class.

view details

Ben Newman

commit sha 5600ca69c7066000ce754eabc36ade77e6986d9e

Update documentation about the options.toReference helper function.

view details

Ben Newman

commit sha 4cca16e448cc1d52069512cde58dfa5603338e6f

Merge pull request #5970 from apollographql/persistent-options.toReference Support toReference(obj, true) to persist obj into cache.

view details

push time in 2 days

PR merged apollographql/apollo-client

Reviewers
Support toReference(obj, true) to persist obj into cache. :bulb: idea 👩‍🏭 refactor 🧞‍♂️ enhancement 🧪 tests

The options.toReference helper function is provided to custom read and merge functions via their options parameter, as well as to cache.modify modifier functions, via their details parameter (#5909). See the tests included in this commit for examples of all three usages.

The original purpose of toReference was to return a Reference object, { __ref: <entity ID> }, given an object with a __typename and the necessary key fields for that type. If these expectations are not met, toReference(obj) can return null, to indicate that the object could not be identified.

Another toReference failure mode (besides returning null) is returning a Reference object that doesn't actually refer to anything stored in the cache. While this case is handled gracefully during cache reads (the non-existent object simply appears empty), you may have encountered cases where you do want to persist the object that was passed to toReference into the cache, such as when a custom read function knows how to provide a perfectly adequate default object based on options.args.

For those use cases, you can now call toReference(object, true) to merge the fields of the object into the cache, assuming it could be identified. Because this merging uses the same EntityStore#merge method as any other cache update, any dependent queries will be appropriately invalidated.

The fields of the object are merged into the cache as-is, without any transformations to handle field arguments, aliases, directives, or variables. For those cases, cache.writeQuery or cache.writeFragment are still the best options. Also, toReference is not exposed outside of read/merge/modify functions, so if you're not in one of those functions you will have to call the normal writeQuery or writeFragment methods.

Implementation-wise, since toReference may now need to call store.merge, it was most convenient to move the definition of the toReference method from the Policies class to the EntityStore class.

+356 -77

1 comment

10 changed files

benjamn

pr closed time in 2 days

create barnchmeteor/meteor

branch : dev-bundle-12.16.1.2

created branch time in 2 days

push eventmeteor/meteor

filipenevola

commit sha 0132191dcd50c0d8923c68557c0222670f3bd09f

Bump Node version to 12.16.1

view details

filipenevola

commit sha 0c7c2a67310227cdb34e88efaadc382977d5261d

Bump $BUNDLE_VERSION to 12.16.1.0 before rebuilding dev bundle.

view details

Ben Newman

commit sha 0743289ff3993f32a6cb1bbcbb39fb6b6aea2a20

Add History.md section for Meteor 1.9.2.

view details

Ben Newman

commit sha 9c852da69599c35e3cf66c5ebed0eabe66bba2ab

Make optimisticLookupPackageJson return array of package.json objects. Commit 646fa4e3ee6baea585766807bc930123ba4d03f7 fixed #10547 by restricting optimisticLookupPackageJson to package.json files with a "name" property, which effectively skipped over intermediate package.json files with additional properties. However, in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick (see packages/modules-runtime/server.js), because ESM modules cannot be imported using require. For example, recent versions of the @babel/runtime package have a @babel/runtime/helpers/esm/package.json file for the ESM versions of its helpers (which specifies "type": "module"), but that package.json file does not have a "name" property, because it is not the root package.json file representing the entire @babel/runtime package. I considered making the "name" restriction configurable, but that would have fragmented the caching of optimisticLookupPackageJson. Instead, I made it return an array of all potentially relevant package.json objects, which can be safely cached. This means that the caller has to iterate over the array, but there is only one call site for this function (in tools/isobuild/package-source.js) right now, so that wasn't too much work.

view details

Ben Newman

commit sha 924c748ecc2d33ee1cddb2af00ecfb5286cf09a8

Avoid bailing out with module.useNode() for ESM modules. On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode() (see packages/modules-runtime/server.js). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works). To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. The good news is that ESM modules don't have access to nearly as many Node.js-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS. If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM using dynamic import(). For now, making sure we avoid bailing out for ESM code like @babel/runtime/helpers/esm/* is the priority.

view details

filipenevola

commit sha dad91bd581822a3e30a66b2cd0cf0b09d50b6b53

Bump package versions for 1.9.2-rc.0 release

view details

Ben Newman

commit sha c81738fbb3af8d38bd8a7c294a750f1697db9ffc

Update meteor-babel to version 7.8.2 and typescript to 3.7.5.

view details

Ben Newman

commit sha ec60e66ef9147ad4d9f8244c8cd27ecd4d610c50

Bump $BUNDLE_VERSION to 12.16.1.1 before rebuilding dev bundle.

view details

Ben Newman

commit sha 60355ae0e308d79dc2ae8a6fd8e6ab8e8d6d3b5e

Bump package versions for 1.9.2-rc.1 release.

view details

filipenevola

commit sha 05e7b81c2a2e166a9a17304b119ef4d57a0f2f4c

Bump package versions for 1.9.2 release

view details

filipenevola

commit sha b96fe01ffa1530b2c07867f942823ab4e3d12111

Updates 1.9.2 release date 2020-02-20

view details

Ben Newman

commit sha 34f88077094f575ebf02bfd6ae06157f372c569a

Merge pull request #10927 from meteor/release-1.9.2 Release 1.9.2

view details

push time in 2 days

PR merged meteor/meteor

Release 1.9.2

For the reasons explained here we are working on Meteor 1.9.2 that will use Node.js 12.16.1

+367 -274

1 comment

16 changed files

filipenevola

pr closed time in 2 days

push eventapollographql/apollo-client

Ben Newman

commit sha 5600ca69c7066000ce754eabc36ade77e6986d9e

Update documentation about the options.toReference helper function.

view details

push time in 2 days

pull request commentapollographql/apollo-client

Set loading to false if data is already in cache

At the very least this logic needs to take the fetchPolicy into account. I can only imagine this being appropriate for the cache-first fetch policy, where the presence of complete cache data means there won't be a network request. For policies like cache-and-network, getting data from the cache definitely does not mean the request is finished!

As a side note, this change triggered a lot of very much related test failures. If you're going to make a small change that has big consequences, at the very least you need to spend some time really understanding why those tests are failing. Just making the most obvious changes to get them to pass is not going to work for us.

vishwam

comment created time in 2 days

PR opened apollographql/apollo-client

Reviewers
Support toReference(obj, true) to persist obj into store. :bulb: idea 👩‍🏭 refactor 🧞‍♂️ enhancement

The options.toReference helper function is provided to custom read and merge functions via their options parameter, as well as to cache.modify modifier functions, via their details parameter (#5909). See the tests included in this commit for examples of all three usages.

The original purpose of toReference was to return a Reference object, { __ref: <entity ID> }, given an object with a __typename and the necessary key fields for that type. If these expectations are not met, toReference(obj) can return null, to indicate that the object could not be identified.

Another toReference failure mode (besides returning null) is returning a Reference object that doesn't actually refer to anything stored in the cache. While this case is handled gracefully during cache reads (the non-existent object simply appears empty), you may have encountered cases where you do want to persist the object that was passed to toReference into the cache, such as when a custom read function knows how to provide a perfectly adequate default object based on options.args.

For those use cases, you can now call toReference(object, true) to merge the fields of the object into the cache, assuming it could be identified. Because this merging uses the same EntityStore#merge method as any other cache update, any dependent queries will be appropriately invalidated.

The fields of the object are merged into the cache as-is, without any transformations to handle field arguments, aliases, directives, or variables. For those cases, cache.writeQuery or cache.writeFragment are still the best options. Also, toReference is not exposed outside of read/merge/modify functions, so if you're not in one of those functions you will have to call the normal writeQuery or writeFragment methods.

Implementation-wise, since toReference may now need to call store.merge, it was most convenient to move the definition of the toReference method from the Policies class to the EntityStore class.

+350 -76

0 comment

9 changed files

pr created time in 3 days

create barnchapollographql/apollo-client

branch : persistent-options.toReference

created branch time in 3 days

delete branch apollographql/apollo-client

delete branch : EntityStore-modify-method

delete time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha 60355ae0e308d79dc2ae8a6fd8e6ab8e8d6d3b5e

Bump package versions for 1.9.2-rc.1 release.

view details

push time in 3 days

created tagmeteor/meteor

tagrelease/METEOR@1.9.2-rc.1

Meteor, the JavaScript App Platform

created time in 3 days

pull request commentmeteor/meteor

Release 1.9.2

@filipenevola The Travis tests that still have the yellow dot for commit seem like they passed without updating the status: https://travis-ci.org/meteor/meteor/builds/652669465

filipenevola

comment created time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha ec60e66ef9147ad4d9f8244c8cd27ecd4d610c50

Bump $BUNDLE_VERSION to 12.16.1.1 before rebuilding dev bundle.

view details

push time in 3 days

create barnchmeteor/meteor

branch : dev-bundle-12.16.1.1

created branch time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha c81738fbb3af8d38bd8a7c294a750f1697db9ffc

Update meteor-babel to version 7.8.2 and typescript to 3.7.5.

view details

push time in 3 days

created tagmeteor/babel

tagv7.8.1

Babel wrapper package for use with Meteor

created time in 3 days

created tagmeteor/babel

tagv7.8.2

Babel wrapper package for use with Meteor

created time in 3 days

push eventmeteor/babel

Ben Newman

commit sha 1b5736283c59f7007cc4e7530b3e57d38be06da9

Update eligible dependencies to latest versions.

view details

Ben Newman

commit sha e949b3622ac898ee5241f412e7fd5e814a52f7ac

Update package-lock.json.

view details

Ben Newman

commit sha b23d0dc31c79b3f02d5fe3ea16ec3754d3273ac9

Bump npm version to 7.8.2 in preparation for publishing.

view details

push time in 3 days

created tagmeteor/babel-preset-meteor

tagv7.8.1

Babel preset for ES2015+ features supported by Meteor

created time in 3 days

push eventmeteor/babel-preset-meteor

Ben Newman

commit sha 06b9167a0497be52ad86d615c9b10de616d9d84d

Update eligible dependencies to latest versions.

view details

Ben Newman

commit sha 7cc3028a934c171d1f376feb4e1a8e659265fe1b

Update package-lock.json.

view details

Ben Newman

commit sha fdb5ddd8a5fbd8181558ad1cf16db19e4afb2824

Bump npm version to 7.8.1 in preparation for publishing.

view details

push time in 3 days

pull request commentfacebook/regenerator

Pass Promise as a parameter to regeneratorRuntime.async()

@nicolo-ribaudo Do you think this should be a minor version bump for regenerator-runtime and/or regenerator-transform, or is it fully backwards compatible?

nicolo-ribaudo

comment created time in 3 days

Pull request review commentfacebook/regenerator

Pass Promise as a parameter to regeneratorRuntime.async()

 var runtime = (function (exports) {   // Note that simple async functions are implemented on top of   // AsyncIterator objects; they just return a Promise for the value of   // the final result produced by the iterator.-  exports.async = function(innerFn, outerFn, self, tryLocsList) {+  exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {+    if (PromiseImpl === undefined) PromiseImpl = Promise;
    if (PromiseImpl === void 0) PromiseImpl = Promise;

A little shorter, if you like.

nicolo-ribaudo

comment created time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha 0743289ff3993f32a6cb1bbcbb39fb6b6aea2a20

Add History.md section for Meteor 1.9.2.

view details

push time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha 290e084cabee7ccf9facabf49d790531f541a2e4

Make optimisticLookupPackageJson return array of package.json objects. Commit 646fa4e3ee6baea585766807bc930123ba4d03f7 fixed #10547 by restricting optimisticLookupPackageJson to package.json files with a "name" property, which effectively skipped over intermediate package.json files with additional properties. However, in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick (see packages/modules-runtime/server.js), because ESM modules cannot be imported using require. For example, recent versions of the @babel/runtime package have a @babel/runtime/helpers/esm/package.json file for the ESM versions of its helpers (which specifies "type": "module"), but that package.json file does not have a "name" property, because it is not the root package.json file representing the entire @babel/runtime package. I considered making the "name" restriction configurable, but that would have fragmented the caching of optimisticLookupPackageJson. Instead, I made it return an array of all potentially relevant package.json objects, which can be safely cached. This means that the caller has to iterate over the array, but there is only one call site for this function (in tools/isobuild/package-source.js) right now, so that wasn't too much work.

view details

Ben Newman

commit sha 87bc54fb9fe0d55251cc0cbdb4066e9103e6c6da

Avoid bailing out with module.useNode() for ESM modules. On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode() (see packages/modules-runtime/server.js). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works). To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. The good news is that ESM modules don't have access to nearly as many Node.js-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS. If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM using dynamic import(). For now, making sure we avoid bailing out for ESM code like @babel/runtime/helpers/esm/* is the priority.

view details

Ben Newman

commit sha 947361bbc8e3ff922dd8a7076a3f5efb6274144b

Merge pull request #10926 from meteor/avoid-module.useNode-for-ESM-imports Avoid bailing out with module.useNode() for ESM modules.

view details

push time in 3 days

delete branch meteor/meteor

delete branch : avoid-module.useNode-for-ESM-imports

delete time in 3 days

PR merged meteor/meteor

Avoid bailing out with module.useNode() for ESM modules.

On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode(). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. This bailout has been in place since Meteor 1.3 (when the module system was first introduced), and it has worked remarkably well.

However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works).

To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. This leads to including ESM modules in the server bundle, rather than relying on Node to execute them directly from the file system.

The good news is that ESM modules don't have access to nearly as many Node/CommonJS-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS.

If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM, perhaps using dynamic import(). For now, making sure we avoid bailing out for ESM code found in @babel/runtime/helpers/esm/* is the priority.

+83 -15

1 comment

4 changed files

benjamn

pr closed time in 3 days

pull request commentmeteor/meteor

Avoid bailing out with module.useNode() for ESM modules.

Here are some examples of the new error reported by Node.js 12.16.0:

Must use import to load ES Module: /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/asyncIterator.js
require() of ES modules is not supported.
require() of /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/asyncIterator.js from /private/var/folders/zb/l6qn64652ljcfb99jlv2s1v80000gn/T/meteor-test-run1rdgzk2.zhmw/.meteor/local/build/programs/server/npm-require.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename asyncIterator.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/package.json.

Error [ERR_REQUIRE_ESM] [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/asyncIterator.js
require() of ES modules is not supported.
require() of /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/asyncIterator.js from npm-require.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename asyncIterator.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/ben/meteor/tools/tests/apps/modules/node_modules/@babel/runtime/helpers/esm/package.json.

None of those suggestions are useful, because we do not control the package in question.

benjamn

comment created time in 3 days

pull request commentmeteor/meteor

Release 1.10

That last test failure is expected (also failing on devel), and should be fixed by https://github.com/meteor/meteor/pull/10926. 🤞

benjamn

comment created time in 3 days

push eventmeteor/meteor

Ben Newman

commit sha 87bc54fb9fe0d55251cc0cbdb4066e9103e6c6da

Avoid bailing out with module.useNode() for ESM modules. On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode() (see packages/modules-runtime/server.js). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works). To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. The good news is that ESM modules don't have access to nearly as many Node.js-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS. If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM using dynamic import(). For now, making sure we avoid bailing out for ESM code like @babel/runtime/helpers/esm/* is the priority.

view details

push time in 3 days

PR opened meteor/meteor

Avoid bailing out with module.useNode() for ESM modules.

On the server, Meteor attempts to avoid bundling node_modules code by replacing entry point modules with a stub that calls module.useNode(). This trick allows evaluating server node_modules natively in Node.js, faithfully preserving all Node-specific behaviors, such as module.id being an absolute file system path, the __dirname and __filename variables, the ability to import binary .node modules, and so on. This bailout has been in place since Meteor 1.3 (when the module system was first introduced), and it has worked remarkably well.

However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated natively by Node are considered ECMAScript modules (ESM) if the closest package.json file has "type": "module" (or has an .mjs file extension). This poses a problem for the module.useNode() trick, because ESM modules cannot be imported synchronously using require (which is currently how module.useNode() works).

To work around this new error, this commit checks package.json for "type": "module" in ImportScanner#shouldUseNode to determine whether it's safe to use the module.useNode() trick. This leads to including ESM modules in the server bundle, rather than relying on Node to execute them directly from the file system.

The good news is that ESM modules don't have access to nearly as many Node/CommonJS-specific quirks: no module, require, or exports variables; no __dirname, no __filename; no ability to import JSON or other non-ESM file types (at least right now). So it seems somewhat less important for ESM code (compared to CommonJS code) to bail out into native Node.js execution using module.useNode(). In other words, bundling server code should not affect its execution in nearly as many cases, if that code is ESM rather than legacy CommonJS.

If this good news turns out to be overly optimistic, we can consider using a different kind of bailout stub that's capable of importing ESM, perhaps using dynamic import(). For now, making sure we avoid bailing out for ESM code found in @babel/runtime/helpers/esm/* is the priority.

+83 -15

0 comment

4 changed files

pr created time in 3 days

create barnchmeteor/meteor

branch : avoid-module.useNode-for-ESM-imports

created branch time in 3 days

push eventmeteor/meteor

filipenevola

commit sha d7bb478a41d61cd6355f554e4d8f4eb68a140ecd

Merge branch 'master' into devel

view details

Tsegaselassie Tadesse

commit sha d3dd0a1756eb42240d32a09b035ca71957c3e9d2

Update Roadmap to nominate lead for Vue.js

view details

filipenevola

commit sha fca6c62d432eff1afd4a67280b7c90af23399511

Bump $BUNDLE_VERSION to 12.16.0.1 before rebuilding dev bundle.

view details

Ben Newman

commit sha 8ff7eed55cf34dfedbc5c3fe17d69407860165e7

Merge branch 'devel' into release-1.10

view details

filipenevola

commit sha c9ea1f427cc514df4d07020eca776f5f9a1704ed

Bump package versions for 1.10-beta.6 release

view details

Ben Newman

commit sha b6320119d4cb6809d63312068dde12b0a4a1510c

Update @babel/* dependencies of modules test app.

view details

Ben Newman

commit sha fc2bdd6ddfe29d5702f9cd0b0a6e281e2e03aa18

Attempt to fix @babel/runtime/helpers/esm/* import test. CircleCI tests will fail for this commit, since these changes do not address the problem that the module.useNode() stub imports the ESM code using require. I will fix the tests properly in a later commit.

view details

push time in 3 days

push eventmeteor/meteor

filipenevola

commit sha d7bb478a41d61cd6355f554e4d8f4eb68a140ecd

Merge branch 'master' into devel

view details

Tsegaselassie Tadesse

commit sha d3dd0a1756eb42240d32a09b035ca71957c3e9d2

Update Roadmap to nominate lead for Vue.js

view details

filipenevola

commit sha fca6c62d432eff1afd4a67280b7c90af23399511

Bump $BUNDLE_VERSION to 12.16.0.1 before rebuilding dev bundle.

view details

push time in 3 days

issue commentapollographql/apollo-client

Use zen-observable as ESM

ESM support is a very recent addition to zen-observable, so I'm sure they would appreciate an issue/PR to add the "module": "esm.js" entry point. You can certainly link back to this issue as supporting evidence, but I believe it's their responsibility to follow the same conventions that other dual CJS/ESM packages follow.

abdonrd

comment created time in 3 days

issue commentapollographql/apollo-client

`gc` function missing from TypeScript definitions for ApolloCache (3.0.0-beta.36)

@hwillson This seems like a quick follow-up to #5956? The default implementation of ApolloCache#gc can just return [], and InMemoryCache will override it with the real implementation.

mattwilson1024

comment created time in 3 days

pull request commentapollographql/apollo-client

Use Boolean function instead of double negation

Care to explain why you believe this is an improvement?

MichaelDeBoey

comment created time in 3 days

created tagapollographql/apollo-client

tagv3.0.0-beta.36

:rocket: A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server

created time in 4 days

push eventapollographql/apollo-client

Ben Newman

commit sha 0540f98af9e46c5cccbd5b5cd4bd03bc6b915aab

Bump @apollo/client npm version to 3.0.0-beta.36.

view details

push time in 4 days

push eventapollographql/apollo-client

Ben Newman

commit sha fadf661074cf7e82461ee45ca5edbc716a0a0f3e

Mention PR #5962 in CHANGELOG.md and comments.

view details

push time in 4 days

delete branch apollographql/apollo-client

delete branch : remove-fixPolyfills.ts

delete time in 4 days

push eventapollographql/apollo-client

Ben Newman

commit sha 107f471c552a208384f276ce0d40b3d5f9cbb0e9

Remove fixPolyfills.ts, except when bundling for React Native. React Native used to have Map and Set polyfills that relied on tagging objects with a special __MAP_POLYFILL_INTERNAL_HASH__ property, which breaks down when the object to be tagged happens to be frozen. In 833072ee11a3c06f7d83964faae02e157f272dfb (#3964) I introduced a workaround to make sure objects got tagged before becoming non-extensible, which robustly solved the problem for any Map and Set polyfills that rely on an object tagging strategy. Note that Apollo Client freezes objects only in development (using maybeDeepFreeze), so the problem fixPolyfills.ts was intended to solve was only ever a problem in development. I also submitted a PR to React Native that make their Map and Set polyfills store non-extensible objects in an array, rather than attempting to tag them: https://github.com/facebook/react-native/pull/21492. Those changes were first released in React Native 0.59.0, so technically the fixPolyfills.ts logic should not be necessary for anyone using that version or later. Since then, React Native has stopped using any polyfills for Map and Set (yay!), so the need for the workaround has been even further reduced: https://github.com/facebook/react-native/commit/93b9ac74e59bbe84ea388d7c1879857b4acab114 Those changes were first released in React Native 0.61.0, which is still the latest minor version (0.61.5 is latest). I'm not sure how many people are still using older versions of React Native, or what sort of LTS policies they have. Expo SDK 36 uses 0.61.4, for what it's worth: https://docs.expo.io/versions/latest/sdk/overview/ In any case, I think we can eliminate these polyfills from the default bundle, as long as we take some care to include them when bundling for React Native. This strategy uses a combination of techniques for selective bundling in React Native: https://facebook.github.io/react-native/docs/platform-specific-code#platform-specific-extensions https://github.com/facebook/react-native/pull/2208

view details

Ben Newman

commit sha 07d052b72a46c064203bc576717b735c42692563

Reduce bundlesize limit back down to 24KB. :tada:

view details

Ben Newman

commit sha fabaa0e2e87fe4e15dc120afdd0cd97e3cda393e

Merge pull request #5962 from apollographql/remove-fixPolyfills.ts Remove fixPolyfills.ts, except when bundling for React Native.

view details

push time in 4 days

PR merged apollographql/apollo-client

Remove fixPolyfills.ts, except when bundling for React Native. :bulb: idea 📦 bundle size 🛠 tooling

React Native used to have Map and Set polyfills that relied on tagging objects with a special __MAP_POLYFILL_INTERNAL_HASH__ property, which breaks down when the object to be tagged happens to be frozen.

In 833072ee11a3c06f7d83964faae02e157f272dfb (#3964) I introduced a workaround to make sure objects got tagged before becoming non-extensible, which robustly solved the problem for any Map and Set polyfills that rely on an object tagging strategy (not just the React Native ones).

Note that Apollo Client freezes objects only in development (using maybeDeepFreeze), so the problem fixPolyfills.ts was intended to solve was only ever a problem in development.

A while back, I submitted this PR to React Native that make their Map and Set polyfills store non-extensible objects in an array, rather than attempting to tag them. Those changes were first released in React Native 0.59.0, so technically the fixPolyfills.ts logic should no longer be necessary for anyone using that version or later.

Since then, React Native has stopped using any polyfills for Map and Set (yay!), so the need for the workaround has been even further reduced: https://github.com/facebook/react-native/commit/93b9ac74e59bbe84ea388d7c1879857b4acab114

Those changes were first released in React Native 0.61.0, which is still the latest minor version (0.61.5 is latest). I'm not sure how many people are still using older versions of React Native, or what sort of LTS policies they have. Expo SDK 36 uses 0.61.4, for what it's worth.

In any case, I think we can eliminate these polyfills from the default bundle, as long as we take some care to include them when bundling for React Native. This strategy uses a combination of techniques for selective bundling in React Native:

  • https://facebook.github.io/react-native/docs/platform-specific-code#platform-specific-extensions
  • https://github.com/facebook/react-native/pull/2208

Non-React Native applications that want to support older JavaScript environments should probably use the core-js polyfills for Map and Set.

+65 -55

2 comments

3 changed files

benjamn

pr closed time in 4 days

pull request commentapollographql/apollo-client

Remove fixPolyfills.ts, except when bundling for React Native.

@hwillson If we were confident that everyone using React Native should be using at least 0.59.0, then we could remove this logic altogether, and avoid the React Native-specific conditional bundling logic.

benjamn

comment created time in 4 days

push eventapollographql/apollo-client

Ben Newman

commit sha 107f471c552a208384f276ce0d40b3d5f9cbb0e9

Remove fixPolyfills.ts, except when bundling for React Native. React Native used to have Map and Set polyfills that relied on tagging objects with a special __MAP_POLYFILL_INTERNAL_HASH__ property, which breaks down when the object to be tagged happens to be frozen. In 833072ee11a3c06f7d83964faae02e157f272dfb (#3964) I introduced a workaround to make sure objects got tagged before becoming non-extensible, which robustly solved the problem for any Map and Set polyfills that rely on an object tagging strategy. Note that Apollo Client freezes objects only in development (using maybeDeepFreeze), so the problem fixPolyfills.ts was intended to solve was only ever a problem in development. I also submitted a PR to React Native that make their Map and Set polyfills store non-extensible objects in an array, rather than attempting to tag them: https://github.com/facebook/react-native/pull/21492. Those changes were first released in React Native 0.59.0, so technically the fixPolyfills.ts logic should not be necessary for anyone using that version or later. Since then, React Native has stopped using any polyfills for Map and Set (yay!), so the need for the workaround has been even further reduced: https://github.com/facebook/react-native/commit/93b9ac74e59bbe84ea388d7c1879857b4acab114 Those changes were first released in React Native 0.61.0, which is still the latest minor version (0.61.5 is latest). I'm not sure how many people are still using older versions of React Native, or what sort of LTS policies they have. Expo SDK 36 uses 0.61.4, for what it's worth: https://docs.expo.io/versions/latest/sdk/overview/ In any case, I think we can eliminate these polyfills from the default bundle, as long as we take some care to include them when bundling for React Native. This strategy uses a combination of techniques for selective bundling in React Native: https://facebook.github.io/react-native/docs/platform-specific-code#platform-specific-extensions https://github.com/facebook/react-native/pull/2208

view details

Ben Newman

commit sha 07d052b72a46c064203bc576717b735c42692563

Reduce bundlesize limit back down to 24KB. :tada:

view details

push time in 4 days

Pull request review commentapollographql/apollo-client

Remove fixPolyfills.ts, except when bundling for React Native.

+// Make sure Map.prototype.set returns the Map instance, per spec.+// https://github.com/apollographql/apollo-client/issues/4024+const testMap = new Map();+if (testMap.set(1, 2) !== testMap) {+  const { set } = testMap;+  Map.prototype.set = function (...args) {

These shims are not specific to React Native, but we also do not rely on the return values of Map.prototype.set or Set.prototype.add anywhere in the Apollo Client codebase anymore. I'm leaving them here so folks can easily find and copy the code if they need it.

benjamn

comment created time in 4 days

push eventapollographql/apollo-client

Ben Newman

commit sha 15005fff582c62aa413dbdce9f2b98abd6bd2df3

Reduce bundlesize limit back down to 24KB. :tada:

view details

push time in 4 days

PR opened apollographql/apollo-client

Reviewers
Remove fixPolyfills.ts, except when bundling for React Native. :bulb: idea 📦 bundle size 🛠 tooling

React Native used to have Map and Set polyfills that relied on tagging objects with a special __MAP_POLYFILL_INTERNAL_HASH__ property, which breaks down when the object to be tagged happens to be frozen.

In 833072ee11a3c06f7d83964faae02e157f272dfb (#3964) I introduced a workaround to make sure objects got tagged before becoming non-extensible, which robustly solved the problem for any Map and Set polyfills that rely on an object tagging strategy (not just the React Native ones).

Note that Apollo Client freezes objects only in development (using maybeDeepFreeze), so the problem fixPolyfills.ts was intended to solve was only ever a problem in development.

A while back, I submitted this PR to React Native that make their Map and Set polyfills store non-extensible objects in an array, rather than attempting to tag them. Those changes were first released in React Native 0.59.0, so technically the fixPolyfills.ts logic should no longer be necessary for anyone using that version or later.

Since then, React Native has stopped using any polyfills for Map and Set (yay!), so the need for the workaround has been even further reduced: https://github.com/facebook/react-native/commit/93b9ac74e59bbe84ea388d7c1879857b4acab114

Those changes were first released in React Native 0.61.0, which is still the latest minor version (0.61.5 is latest). I'm not sure how many people are still using older versions of React Native, or what sort of LTS policies they have. Expo SDK 36 uses 0.61.4, for what it's worth.

In any case, I think we can eliminate these polyfills from the default bundle, as long as we take some care to include them when bundling for React Native. This strategy uses a combination of techniques for selective bundling in React Native:

  • https://facebook.github.io/react-native/docs/platform-specific-code#platform-specific-extensions
  • https://github.com/facebook/react-native/pull/2208

Non-React Native applications that want to support older JavaScript environments should probably use the core-js polyfills for Map and Set.

+61 -54

0 comment

3 changed files

pr created time in 4 days

create barnchapollographql/apollo-client

branch : remove-fixPolyfills.ts

created branch time in 4 days

issue commentwhatwg/html

Proposal: import.meta.resolveURL

@domenic Ahh, thanks for clarifying that distinction.

Are you envisioning a world where we have both import.meta.resolveURL and import.meta.resolve at the same time (at least in browsers)? I don't have any objections to having both, I'm just curious about the relationship between the proposals, if you have thoughts.

By the way, @guybedford directed me to his PR adding support for import.meta.resolve to Node.js, and it looks like my use case will be covered by that API (at least for Node): https://github.com/WICG/import-maps/issues/79#issuecomment-587365134

guybedford

comment created time in 4 days

issue commentWICG/import-maps

How could import.meta.resolve() behave?

@guybedford Thank you so much for working on that!

domenic

comment created time in 4 days

issue commentapollographql/apollo-client

Use zen-observable as ESM

Here's where we import Observable from "zen-observable". As you can see, we're not doing anything that would force your bundler to import the CommonJS entry point, and the version constraint in our package.json (^0.8.14) permits installing the latest version of zen-observable, which is just 0.8.15. In short, I don't think Apollo Client is standing in the way of using the new ESM entry point. Let me know if there's something concrete you want us to do here.

abdonrd

comment created time in 4 days

issue commentapollographql/apollo-client

typePolicies exisitngData arg is incorrect or missused

@atbtechgit A reproduction in a new issue would be great, unless either of these questions leads somewhere:

  • Do any other read functions get called correctly? Is this problem specific to Query.book?
  • Are you using query { book @client } in your query, or just query { book }?
tafelito

comment created time in 5 days

issue commentwhatwg/html

Proposal: import.meta.resolveURL

Is there any chance of allowing import.meta.resolveURL(id, parentURL) to specify a parentURL that's different from import.meta.url?

I'd like to be able to follow a chain of relative imports in a reliable way (respecting import maps and all that), and it doesn't seem possible to retrieve the import.meta.resolve function from an arbitrary module.

I'm happy to be redirected to any prior discussion of this topic, of course.

guybedford

comment created time in 5 days

issue commentWICG/import-maps

How could import.meta.resolve() behave?

I could definitely work with a version of import.meta.resolve that returned a Promise. That seems future-proof, and an easy to explain, even without top-level await to help with the ergonomics.

I share @guybedford's concerns about fallback performance/predictability and would probably avoid using fallbacks personally, but I appreciate the importance of making the API consistently async.

In the future, we might come up with additional reasons (even more compelling than fallback support) why module resolution needs to be async, and I think we'd be glad we chose a generic solution to the problem (such as returning a Promise) rather than something specific to fallbacks. Returning an array of URLs feels somewhat fallback-specific, to me.

On a different note, would it be possible to do import.meta.resolve(identifier, parentURL) to use a parent URL that's different from import.meta.url?

domenic

comment created time in 5 days

Pull request review commentapollographql/apollo-client

Mutate update function DataProxy/ApolloCache changes

 export abstract class ApolloCache<TSerialized> implements DataProxy {    */   public abstract extract(optimistic?: boolean): TSerialized; -  // optimistic API+  // Optimistic API+   public abstract removeOptimistic(id: string): void; -  // transactional API+  // Transactional API+   public abstract performTransaction(     transaction: Transaction<TSerialized>,   ): void;+   public abstract recordOptimisticTransaction(     transaction: Transaction<TSerialized>,     id: string,   ): void; -  // optional API+  // Optional API+   public transformDocument(document: DocumentNode): DocumentNode {     return document;   }-  // experimental++  public identify(object: StoreObject): string | null {

I think evict is already exposed?

I was going to say gc is too implementation-specific to expose here, but modify is pretty specific too, and I'm sure the Hermes ApolloCache implementation would want to implement gc if it was an official part of the API, so I think I'm leaning towards exposing gc as well! Of course we can easily provide a no-op default implementation that doesn't collect anything.

hwillson

comment created time in 5 days

pull request commentapollographql/apollo-client

Various cache read and write performance optimizations.

These changes have been released in @apollo/client@3.0.0-beta.35, fyi.

benjamn

comment created time in 5 days

Pull request review commentapollographql/apollo-client

Mutate update function DataProxy/ApolloCache changes

+import { SelectionSetNode } from 'graphql';++import {+  isReference,+  StoreValue,+  StoreObject,+  Reference+} from '../../../utilities/graphql/storeUtils';+import { FragmentMap } from '../../../utilities/graphql/fragments';++// The Readonly<T> type only really works for object types, since it marks+// all of the object's properties as readonly, but there are many cases when+// a generic type parameter like TExisting might be a string or some other+// primitive type, in which case we need to avoid wrapping it with Readonly.+// SafeReadonly<string> collapses to just string, which makes string+// assignable to SafeReadonly<any>, whereas string is not assignable to+// Readonly<any>, somewhat surprisingly.+export type SafeReadonly<T> = T extends object ? Readonly<T> : T;++export type Modifier<T> = (value: T, details: {

I have no problem with putting these types in the (cache) core. We’re making them part of the abstract ApolloCache API, so they belong in the core!

hwillson

comment created time in 5 days

issue commentapollographql/apollo-client

Cache FieldPolicy.merge receives stale args when using fetchMore

I think you should be using params.args.offset instead of params.variables.offset, though I'm not sure if that will fix your problem.

cbergmiller

comment created time in 6 days

delete branch apollographql/apollo-client

delete branch : read-and-write-performance-optimizations

delete time in 6 days

push eventapollographql/apollo-client

Ben Newman

commit sha f08ab2a6d39ca12b1618a1fcabd468fe2a1fb055

Fix comment in makeDepKey. Follow-up to 794554405bfb46298842cb5b21ffff507b868cde.

view details

push time in 6 days

created tagapollographql/apollo-client

tagv3.0.0-beta.35

:rocket: A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server

created time in 6 days

push eventapollographql/apollo-client

Ben Newman

commit sha 3bb384dff617203e677ad5582f28e09662e51f9d

Bump @apollo/client npm version to 3.0.0-beta.35.

view details

push time in 6 days

push eventapollographql/apollo-client

Ben Newman

commit sha d6edbaef76aa1dedf5a146e110a79141bc7dd3ea

Use Set for DeepMerger pastCopies instead of array/indexOf. When I wrote this code, I thought this array would usually be so short that indexOf would be faster than Set.prototype.has, but of course the pathological cases are what end up mattering, and I've recently seen some result objects that cause thousands of shallow copies to be made over a series of many merges using one DeepMerger instance.

view details

Ben Newman

commit sha db1a73dadd364066c0a29c7b1ad87a39c5c7a7d7

Optimize shouldInclude for common case of no directives. Since shouldInclude gets called for every single field in any read or write operation, it's important that it takes any available shortcuts to handle the common case (no directives) as cheaply as possible.

view details

Ben Newman

commit sha 96b5a64434b839203cda048ef5c29d59b221d145

Avoid repeatedly encoding context.variables with JSON.stringify. Since any of the provided variables could be consumed by any of the fields in a selection set that we're reading, all variables are potentially relevant as part of the result object cache key, so we don't make any attempt to stringify just a subset of the variables. However, since we use the same stringified variables in every cache key, there's no need to perform that encoding repeatedly. JSON.stringify may be fast, but the variables object can be arbitrarily large.

view details

Ben Newman

commit sha 0c6ee74e14dc71b8ba651f4d949a8542632ca406

Track policies.rootIdsByTypename as well as policies.rootTypenamesById. Believe it or not, iterating over the values of policies.rootTypenamesById was noticeably expensive according to Chrome devtools profiling. Since this information almost never changes, we might as well maintain it in the format that's most convenient.

view details

Ben Newman

commit sha 1b8208e3d4793486c60d1f6b4cae600c7875a418

Avoid using JSON.stringify([...]) in makeDepKey helper function. Creating a throwaway array just to call JSON.stringify was much more expensive than string concatenation. The exact format of these cache keys is an invisible implementation detail, so I picked something that seemed unlikely ever to be ambiguous, though we can easily change it later.

view details

Ben Newman

commit sha e3dd0b9290c79d170fefdb722148c21521bbe4d5

Avoid calling policies.applyMerges unless mergeable fields found. Since policies.applyMerges doesn't change anything unless there are custom merge functions to process, we can skip calling it if no merge functions were found while processing the current entity.

view details

Ben Newman

commit sha 852681d6834ce9b21af73bd8701d579c7b9467ef

Avoid forEach and fragment recursion in processSelectionSet. Instead of recursively calling processSelectionSet to handle fragments, we can simply treat their fields as fields of the current selection set.

view details

Ben Newman

commit sha df20ff54090dee769b3114e3aec499b18543cb95

Avoid forEach and fragment recursion in executeSelectionSet. This change means fragment results will no longer be cached separately from normal selection set results, which is potentially a loss of caching granularity, but there's also a reduction in caching overhead because we're caching fewer result objects, and we don't have to merge them all together, and (most importantly) the result caching system still tracks dependencies the same way as before. It's as if we transformed the query by inlining fragment selections, except without doing any work!

view details

Ben Newman

commit sha dc61865bc267e6cb21aad6c29ef1b07c3362ed29

Use a Set to process and deduplicate fields. Although this may seem like a reversion to forEach instead of a for loop, the for loop had an unexpectedly negative impact on minification, and a Set has the ability to deduplicate selection objects, so we never re-process the same field multiple times through different fragments.

view details

Ben Newman

commit sha 794554405bfb46298842cb5b21ffff507b868cde

Use '#' rather than '\n' to join field name and ID in makeDepKey. https://github.com/apollographql/apollo-client/pull/5948#discussion_r379825702

view details

Ben Newman

commit sha 0a4ae816ad4ae50243a75af179c720a8839bd042

Mention PR #5948 in CHANGELOG.md.

view details

Ben Newman

commit sha b094e30b052783e1fe6c4b43bca1303ad7ab6450

Merge pull request #5948 from apollographql/read-and-write-performance-optimizations Various cache read and write performance optimizations.

view details

push time in 6 days

PR merged apollographql/apollo-client

Reviewers
Various cache read and write performance optimizations. :bulb: idea :racehorse: performance 🧞‍♂️ enhancement

Although we've been building Apollo Client 3.0 with performance in mind, making sure (for example) that you only pay for the features you use, we haven't focused on optimizing raw performance per se, until now.

Using an especially large query and response object provided by a customer/contributor, I was able to reduce initial (cold) execution times for the following write/read round-trip from ~150ms (measured using the latest published beta, @apollo/client@3.0.0-beta.34) to to ~95ms, a 37% improvement, and average (warm) execution times from ~105ms to ~25ms, a 76% improvement:

const start = Date.now();

cache.writeQuery({
  query,
  data: result.data,
  variables,
});

cache.watch({
  query,
  variables,
  optimistic: true,
  immediate: true,
  callback(data) {
    console.log(Date.now() - start, "ms");
  },
});

For this benchmark, I created a new InMemoryCache object for each run, so the results are not skewed by the benefits of result caching (see #3394) though result caching can have huge benefits for actual applications.

As always with performance, exact numbers will vary from query to query and machine to machine, but I used a 2014 dual-core 3GHz MacBook Pro, a 36KB query with lots of fragments, and a 500KB JSON-encoded result.

It's worth reviewing each of these commits separately, as they do not really follow a common theme (except for speeeed :feelsgood:).

+132 -106

0 comment

7 changed files

benjamn

pr closed time in 6 days

push eventapollographql/apollo-client

Ben Newman

commit sha 0a4ae816ad4ae50243a75af179c720a8839bd042

Mention PR #5948 in CHANGELOG.md.

view details

push time in 6 days

push eventapollographql/apollo-client

Ben Newman

commit sha 794554405bfb46298842cb5b21ffff507b868cde

Use '#' rather than '\n' to join field name and ID in makeDepKey. https://github.com/apollographql/apollo-client/pull/5948#discussion_r379825702

view details

push time in 6 days

Pull request review commentapollographql/apollo-client

Various cache read and write performance optimizations.

 class CacheGroup { }  function makeDepKey(dataId: string, storeFieldName: string) {-  return JSON.stringify([dataId, fieldNameFromStoreName(storeFieldName)]);+  // Since field names cannot have newline characters in them, this method+  // of joining the field name and the ID should be unambiguous, and much+  // cheaper than JSON.stringify([dataId, fieldName]).+  return fieldNameFromStoreName(storeFieldName) + "\n" + dataId;

These keys really are invisible unless you go spelunking into the optimism library. In some other cases (see makeCacheKey) we use empty object references as keys, and {} is about as useless for debugging as you can get, but nobody has complained about that so far. That said, I think I might change it to #, since it precedes an ID.

benjamn

comment created time in 6 days

push eventapollographql/apollo-client

Ben Mosher

commit sha 550e42ed3f0c88dcfee80490334b9f0f344a55c5

tighten QueryTuple to indicate observable fields may be absent if called==false fixes #5933

view details

Ben Mosher

commit sha 73659fc5256b21f2f3994fa72a1f2d5fb3f9ea41

full QueryResult always implies `called: true` (#5933)

view details

Renovate Bot

commit sha 3305a8ae31e0b3969ff27d5aa3d8a01fa6e33bbd

chore(deps): update dependency codecov to v3.6.5

view details

Renovate Bot

commit sha d5de75a604637f1e48f4650f18ea678d3a6f42d8

chore(deps): update dependency graphql to v14.6.0

view details

Renovate Bot

commit sha e2ea17cc449cfe6d813d996c16634c66caa7e329

chore(deps): update dependency gatsby to v2.19.17

view details

Renovate Bot

commit sha f08782bf3a2f7ef4e045e10d70c7a21dedd0bdd9

chore(deps): update dependency react-scripts to v3.4.0

view details

hwillson

commit sha 86a1b25c0119f61003fd27979616168adad40780

Prevent @client @export from firing unnecessary network requests PR https://github.com/apollographql/apollo-client/pull/4604 fixed an issue where changes made to `@client @export` based variables didn't always result in re-running the query that was using the variable. Unfortunately, these changes are a bit too aggressive. They're triggering a `refetch` when an `@client @export` based variable changes (and a few additional conditions are met), and while using the `ObservableQuery.refetch()` method does fix the original issue, it leads to a situation where the query being re-run is always fired over the network, even if the updated query could have been resolved from the cache. `ObservableQuery.refetch()` forces queries to use a network based fetch policy, which means if the query was originally fired with a `cache-first` policy (for example), and has matching data in the cache after taking into consideration the new variable, that data won't be used and instead an extra unnecessary network request will fire. This commit addresses the issue by leveraging `ObservableQuery.setVariables()` instead of automatically refetching. `setVariables` will attempt to resolve the updated query from the cache first, then only fire it over the network if required.

view details

Hugh Willson

commit sha 7cbfcf7dbfc046294bdd58d6b4f2ba9892c09f6d

Merge pull request #5946 from apollographql/prevent-extra-client-export-requests Prevent @client @export from firing unnecessary network requests

view details

Hugh Willson

commit sha 8ec3672ab70b2169d7e072014548fbe890f75b85

Merge pull request #5935 from answerrocket/benmosher/lazy-result tighten QueryTuple to indicate observable fields may be absent

view details

hwillson

commit sha 7c89a0d61c3c072fb590e4b7bb68ad144b719192

Changelog update for #5935

view details

Ben Newman

commit sha d6edbaef76aa1dedf5a146e110a79141bc7dd3ea

Use Set for DeepMerger pastCopies instead of array/indexOf. When I wrote this code, I thought this array would usually be so short that indexOf would be faster than Set.prototype.has, but of course the pathological cases are what end up mattering, and I've recently seen some result objects that cause thousands of shallow copies to be made over a series of many merges using one DeepMerger instance.

view details

Ben Newman

commit sha db1a73dadd364066c0a29c7b1ad87a39c5c7a7d7

Optimize shouldInclude for common case of no directives. Since shouldInclude gets called for every single field in any read or write operation, it's important that it takes any available shortcuts to handle the common case (no directives) as cheaply as possible.

view details

Ben Newman

commit sha 96b5a64434b839203cda048ef5c29d59b221d145

Avoid repeatedly encoding context.variables with JSON.stringify. Since any of the provided variables could be consumed by any of the fields in a selection set that we're reading, all variables are potentially relevant as part of the result object cache key, so we don't make any attempt to stringify just a subset of the variables. However, since we use the same stringified variables in every cache key, there's no need to perform that encoding repeatedly. JSON.stringify may be fast, but the variables object can be arbitrarily large.

view details

Ben Newman

commit sha 0c6ee74e14dc71b8ba651f4d949a8542632ca406

Track policies.rootIdsByTypename as well as policies.rootTypenamesById. Believe it or not, iterating over the values of policies.rootTypenamesById was noticeably expensive according to Chrome devtools profiling. Since this information almost never changes, we might as well maintain it in the format that's most convenient.

view details

Ben Newman

commit sha 1b8208e3d4793486c60d1f6b4cae600c7875a418

Avoid using JSON.stringify([...]) in makeDepKey helper function. Creating a throwaway array just to call JSON.stringify was much more expensive than string concatenation. The exact format of these cache keys is an invisible implementation detail, so I picked something that seemed unlikely ever to be ambiguous, though we can easily change it later.

view details

Ben Newman

commit sha e3dd0b9290c79d170fefdb722148c21521bbe4d5

Avoid calling policies.applyMerges unless mergeable fields found. Since policies.applyMerges doesn't change anything unless there are custom merge functions to process, we can skip calling it if no merge functions were found while processing the current entity.

view details

Ben Newman

commit sha 852681d6834ce9b21af73bd8701d579c7b9467ef

Avoid forEach and fragment recursion in processSelectionSet. Instead of recursively calling processSelectionSet to handle fragments, we can simply treat their fields as fields of the current selection set.

view details

Ben Newman

commit sha df20ff54090dee769b3114e3aec499b18543cb95

Avoid forEach and fragment recursion in executeSelectionSet. This change means fragment results will no longer be cached separately from normal selection set results, which is potentially a loss of caching granularity, but there's also a reduction in caching overhead because we're caching fewer result objects, and we don't have to merge them all together, and (most importantly) the result caching system still tracks dependencies the same way as before. It's as if we transformed the query by inlining fragment selections, except without doing any work!

view details

Ben Newman

commit sha dc61865bc267e6cb21aad6c29ef1b07c3362ed29

Use a Set to process and deduplicate fields. Although this may seem like a reversion to forEach instead of a for loop, the for loop had an unexpectedly negative impact on minification, and a Set has the ability to deduplicate selection objects, so we never re-process the same field multiple times through different fragments.

view details

push time in 6 days

pull request commentapollographql/apollo-client

Implement InMemoryCache#modify for surgically transforming fields.

@dodas Yes, cache.watch listeners will be called—unless you return exactly (===) the same values from the modifier functions (unusual but definitely possible).

If you're not seeing the UI update, the cache.watch broadcast might not be properly followed by a call to client.queryManager.broadcastQueries(). This is an area where we're actively working to make the notification pipeline more robust and less manual, but there are currently some known issues. Happy to help debug/fix any reproduction you can share!

benjamn

comment created time in 6 days

Pull request review commentapollographql/apollo-client

Prevent @client @export from firing unnecessary network requests

 export class ObservableQuery<       iterateObserversSafely(this.observers, 'error', this.lastError = error);     }; +    const {+      hasClientExports,+      serverQuery+    } = queryManager.transform(this.options.query);+     queryManager.observeQuery<TData>(queryId, this.options, {       next: (result: ApolloQueryResult<TData>) => {         if (this.lastError || this.isDifferentFromLastResult(result)) {           const previousResult = this.updateLastResult(result);+           const { query, variables, fetchPolicy } = this.options;            // Before calling `next` on each observer, we need to first see if           // the query is using `@client @export` directives, and update           // any variables that might have changed. If `@export` variables have-          // changed, and the query is calling against both local and remote-          // data, a refetch is needed to pull in new data, using the-          // updated `@export` variables.-          if (queryManager.transform(query).hasClientExports) {+          // changed, and the query is requesting both local and remote+          // data, `setVariables` is used as a network refetch might be+          // needed to pull in new data, using the updated `@export` variables.+          if (hasClientExports) {             queryManager.getLocalState().addExportedVariables(               query,               variables,             ).then((variables: TVariables) => {               const previousVariables = this.variables;-              this.variables = this.options.variables = variables;               if (                 !result.loading &&                 previousResult &&                 fetchPolicy !== 'cache-only' &&-                queryManager.transform(query).serverQuery &&+                serverQuery &&                 !equal(previousVariables, variables)               ) {-                this.refetch();+                this.setVariables(variables).then(updatedResult => {+                  this.variables = this.options.variables = variables;

I think this.setVariables will do this assignment for you (here), so you can remove this line?

hwillson

comment created time in 8 days

push eventapollographql/apollo-client

Ben Newman

commit sha 54d6ed25a082707178496ed67106b30b58578613

Increase bundlesize limit to 24.2KB.

view details

push time in 8 days

PR opened apollographql/apollo-client

Reviewers
Various cache read and write performance optimizations. :bulb: idea :racehorse: performance 🧞‍♂️ enhancement

Although we've been building Apollo Client 3.0 with performance in mind, making sure (for example) that you only pay for the features you use, we haven't focused on optimizing raw performance per se, until now.

Using an especially large query and response object provided by a customer/contributor, I was able to reduce initial (cold) execution times for the following code from 150ms (using the latest published beta, @apollo/client@3.0.0-beta.34) to to 95ms, a 37% improvement, and average (warm) execution times from 105ms to 25ms, a 76% improvement:

cache.writeQuery({
  query,
  data: result.data,
  variables,
});

function read() {
  return new Promise(resolve => {
    cache.watch({
      query,
      variables,
      optimistic: true,
      immediate: true,
      callback: resolve,
    });
  });
}

Promise.all([
  // Doing more than one read() here has almost no effect on performance,
  // thanks to the result caching system.
  read(),
  read(),
  read(),
]).then(() => {
  console.log(Date.now() - start, "ms");
});

As always with performance, exact numbers will vary from query to query and machine to machine, but I used a 2014 dual-core 3GHz MacBook Pro, a 36KB query and 500KB JSON-encoded result.

It's worth reviewing each of these commits separately, as they do not really follow a common theme (except for speeeed :feelsgood:).

+140 -109

0 comment

6 changed files

pr created time in 8 days

issue commentapollographql/apollo-client

update a specific property inside object which is stored inside cache

See #5909, though you will probably need the objects in data.people to have __typename: "Person" so that an ID can be computed for them.

unutoiul

comment created time in 8 days

issue commentapollographql/apollo-client

Data is undefined on cold cache start

@dilame Just to be sure I'm understanding, are you calling client.query (which returns a single Promise), as opposed to using client.watchQuery or useQuery or something that can receive multiple results? If so, then this is definitely a bug.

dilame

comment created time in 8 days

more