From e53c6ce2f7efab7471c4731ffbc31169cfec7a75 Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Mon, 16 Dec 2024 12:54:19 +0100 Subject: [PATCH 1/2] Increase print/visit performance Co-Authored-By: Benjie --- benchmark/fixtures.js | 5 +++ benchmark/kitchen-sink.graphql | 65 ++++++++++++++++++++++++++++++++++ benchmark/printer-benchmark.js | 16 +++++++++ src/language/visitor.ts | 23 ++++++++---- 4 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 benchmark/kitchen-sink.graphql create mode 100644 benchmark/printer-benchmark.js diff --git a/benchmark/fixtures.js b/benchmark/fixtures.js index d057a80526..8f3aa1edd8 100644 --- a/benchmark/fixtures.js +++ b/benchmark/fixtures.js @@ -8,6 +8,11 @@ exports.bigSchemaSDL = fs.readFileSync( 'utf8', ); +exports.bigDocumentSDL = fs.readFileSync( + path.join(__dirname, 'kitchen-sink.graphql'), + 'utf8', +); + exports.bigSchemaIntrospectionResult = JSON.parse( fs.readFileSync(path.join(__dirname, 'github-schema.json'), 'utf8'), ); diff --git a/benchmark/kitchen-sink.graphql b/benchmark/kitchen-sink.graphql new file mode 100644 index 0000000000..8d9c6ab341 --- /dev/null +++ b/benchmark/kitchen-sink.graphql @@ -0,0 +1,65 @@ +query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { + whoever123is: node(id: [123, 456]) { + id + ... on User @onInlineFragment { + field2 { + id + alias: field1(first: 10, after: $foo) @include(if: $foo) { + id + ...frag @onFragmentSpread + } + } + } + ... @skip(unless: $foo) { + id + } + ... { + id + } + } +} + +mutation likeStory @onMutation { + like(story: 123) @onField { + story { + id @onField + } + } +} + +subscription StoryLikeSubscription( + $input: StoryLikeSubscribeInput @onVariableDefinition +) @onSubscription { + storyLikeSubscribe(input: $input) { + story { + likers { + count + } + likeSentence { + text + } + } + } +} + +fragment frag on Friend @onFragmentDefinition { + foo( + size: $size + bar: $b + obj: { + key: "value" + block: """ + block string uses \""" + """ + } + ) +} + +{ + unnamed(truthy: true, falsy: false, nullish: null) + query +} + +query { + __typename +} diff --git a/benchmark/printer-benchmark.js b/benchmark/printer-benchmark.js new file mode 100644 index 0000000000..6227122b89 --- /dev/null +++ b/benchmark/printer-benchmark.js @@ -0,0 +1,16 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { print } = require('graphql/language/printer.js'); + +const { bigDocumentSDL } = require('./fixtures.js'); + +const document = parse(bigDocumentSDL); + +module.exports = { + name: 'Print kitchen sink document', + count: 1000, + measure() { + print(document); + }, +}; diff --git a/src/language/visitor.ts b/src/language/visitor.ts index daf96497bf..3b55ef78c8 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -222,12 +222,23 @@ export function visit( } } } else { - node = Object.defineProperties( - {}, - Object.getOwnPropertyDescriptors(node), - ); - for (const [editKey, editValue] of edits) { - node[editKey] = editValue; + const descriptors = Object.getOwnPropertyDescriptors(node); + node = { ...node }; + for (const nodeKey of Object.keys(descriptors)) { + if (!(nodeKey in node)) { + const descriptor = descriptors[nodeKey]; + if ( + descriptor.enumerable && + descriptor.configurable && + descriptor.writable && + !descriptor.get && + !descriptor.set + ) { + // We already own this by means of the spread + } else { + Object.defineProperty(node, nodeKey, descriptor); + } + } } } } From 30e61f3f966744d78c4a6eac0acc85fc8de859db Mon Sep 17 00:00:00 2001 From: jdecroock Date: Mon, 16 Dec 2024 14:26:36 +0100 Subject: [PATCH 2/2] Simple approach --- src/language/visitor.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/language/visitor.ts b/src/language/visitor.ts index 3b55ef78c8..b392feeff0 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -222,23 +222,9 @@ export function visit( } } } else { - const descriptors = Object.getOwnPropertyDescriptors(node); node = { ...node }; - for (const nodeKey of Object.keys(descriptors)) { - if (!(nodeKey in node)) { - const descriptor = descriptors[nodeKey]; - if ( - descriptor.enumerable && - descriptor.configurable && - descriptor.writable && - !descriptor.get && - !descriptor.set - ) { - // We already own this by means of the spread - } else { - Object.defineProperty(node, nodeKey, descriptor); - } - } + for (const [editKey, editValue] of edits) { + node[editKey] = editValue; } } }