@graphcommerce/graphql 6.0.2-canary.9 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/components/GraphQLProvider.tsx +26 -16
- package/lib/hyperlinker.ts +84 -0
- package/measurePerformanceLink.ts +61 -30
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 6.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1869](https://github.com/graphcommerce-org/graphcommerce/pull/1869) [`82111fa35`](https://github.com/graphcommerce-org/graphcommerce/commit/82111fa351b68a76ff053ebb7e0261ee507a826d) - Faster page rendering on all pages that use Apollo Client: Revert to classical useEffect strategy for Apollo cache persist restore and remove custom hydration strategies from the cart/customer.
|
|
8
|
+
|
|
9
|
+
This comes with a caviat: When using `<Suspense>` to defer rendering you might run into hydration errors. In the case where the Suspense boundaries are used to improve performance, you are required to remove those. We have a follow-up [PR](https://github.com/graphcommerce-org/graphcommerce/pull/1878) in the works that allows getting the hydration performance improvement, but not have the hydration errors. ([@paales](https://github.com/paales))
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#1883](https://github.com/graphcommerce-org/graphcommerce/pull/1883) [`ede93ae7f`](https://github.com/graphcommerce-org/graphcommerce/commit/ede93ae7f1d9239d1e827cce574085a1c264890b) - When running in dev mode, the CLI will now have clickable references to the backend queries made by the Mesh. ([@paales](https://github.com/paales))
|
|
14
|
+
|
|
15
|
+
## 6.0.2-canary.22
|
|
16
|
+
|
|
17
|
+
## 6.0.2-canary.21
|
|
18
|
+
|
|
19
|
+
## 6.0.2-canary.20
|
|
20
|
+
|
|
21
|
+
## 6.0.2-canary.19
|
|
22
|
+
|
|
23
|
+
## 6.0.2-canary.18
|
|
24
|
+
|
|
25
|
+
## 6.0.2-canary.17
|
|
26
|
+
|
|
27
|
+
## 6.0.2-canary.16
|
|
28
|
+
|
|
29
|
+
## 6.0.2-canary.15
|
|
30
|
+
|
|
31
|
+
## 6.0.2-canary.14
|
|
32
|
+
|
|
33
|
+
## 6.0.2-canary.13
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- [#1869](https://github.com/graphcommerce-org/graphcommerce/pull/1869) [`82111fa35`](https://github.com/graphcommerce-org/graphcommerce/commit/82111fa351b68a76ff053ebb7e0261ee507a826d) - Revert to classical useEffect strategy for Apollo cache persist restore and remove custom hydration strategies from the cart. ([@paales](https://github.com/paales))
|
|
38
|
+
|
|
39
|
+
## 6.0.2-canary.12
|
|
40
|
+
|
|
41
|
+
## 6.0.2-canary.11
|
|
42
|
+
|
|
43
|
+
## 6.0.2-canary.10
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- [#1883](https://github.com/graphcommerce-org/graphcommerce/pull/1883) [`ede93ae7f`](https://github.com/graphcommerce-org/graphcommerce/commit/ede93ae7f1d9239d1e827cce574085a1c264890b) - Added clickable links to measurePerformanceLink ([@paales](https://github.com/paales))
|
|
48
|
+
|
|
3
49
|
## 6.0.2-canary.9
|
|
4
50
|
|
|
5
51
|
## 6.0.2-canary.8
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
HttpLink,
|
|
9
9
|
} from '@apollo/client'
|
|
10
10
|
import type { AppProps } from 'next/app'
|
|
11
|
-
import { useState } from 'react'
|
|
11
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
12
12
|
import { createCacheReviver } from '../createCacheReviver'
|
|
13
13
|
import { errorLink } from '../errorLink'
|
|
14
14
|
import fragments from '../generated/fragments.json'
|
|
@@ -46,30 +46,40 @@ export function GraphQLProvider(props: GraphQLProviderProps) {
|
|
|
46
46
|
const { children, policies = [], migrations = [], links = [], pageProps } = props
|
|
47
47
|
const state = (pageProps as { apolloState?: NormalizedCacheObject }).apolloState
|
|
48
48
|
|
|
49
|
+
const stateRef = useRef(state)
|
|
50
|
+
|
|
51
|
+
const linksRef = useRef(links)
|
|
52
|
+
const policiesRef = useRef(policies)
|
|
53
|
+
|
|
54
|
+
const createCache = useCallback(
|
|
55
|
+
() =>
|
|
56
|
+
new InMemoryCache({
|
|
57
|
+
possibleTypes: fragments.possibleTypes,
|
|
58
|
+
typePolicies: mergeTypePolicies(policiesRef.current),
|
|
59
|
+
}),
|
|
60
|
+
[],
|
|
61
|
+
)
|
|
62
|
+
|
|
49
63
|
const [client] = useState(() => {
|
|
50
64
|
const link = ApolloLink.from([
|
|
51
65
|
...(typeof window === 'undefined' ? [errorLink, measurePerformanceLink] : []),
|
|
52
|
-
...
|
|
66
|
+
...linksRef.current,
|
|
53
67
|
// The actual Http connection to the Mesh backend.
|
|
54
68
|
new HttpLink({ uri: '/api/graphql', credentials: 'same-origin' }),
|
|
55
69
|
])
|
|
56
70
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
possibleTypes: fragments.possibleTypes,
|
|
60
|
-
typePolicies: mergeTypePolicies(policies),
|
|
61
|
-
})
|
|
71
|
+
const cache = createCache()
|
|
72
|
+
if (stateRef.current) cache.restore(stateRef.current)
|
|
62
73
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
cache: createCache(),
|
|
66
|
-
name: 'web',
|
|
67
|
-
ssrMode: typeof window === 'undefined',
|
|
68
|
-
})
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
70
|
-
createCacheReviver(apolloClient, createCache, policies, migrations, state)
|
|
71
|
-
return apolloClient
|
|
74
|
+
const ssrMode = typeof window === 'undefined'
|
|
75
|
+
return new ApolloClient({ link, cache, name: 'web', ssrMode })
|
|
72
76
|
})
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
80
|
+
createCacheReviver(client, createCache, policies, migrations, state)
|
|
81
|
+
}, [client, createCache, migrations, policies, state])
|
|
82
|
+
|
|
73
83
|
globalApolloClient.current = client
|
|
74
84
|
|
|
75
85
|
return <ApolloProvider client={globalApolloClient.current}>{children}</ApolloProvider>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
A hyperlink is opened upon encountering an OSC 8 escape sequence with the target URI. The syntax is
|
|
5
|
+
OSC 8 ; params ; URI BEL|ST
|
|
6
|
+
Following this, all subsequent cells that are painted are hyperlinks to this target. A hyperlink is closed with the same escape sequence, omitting the parameters and the URI but keeping the separators:
|
|
7
|
+
OSC 8 ; ; BEL|ST
|
|
8
|
+
const ST = '\u001B\\';
|
|
9
|
+
*/
|
|
10
|
+
const OSC = '\u001B]'
|
|
11
|
+
const BEL = '\u0007'
|
|
12
|
+
const SEP = ';'
|
|
13
|
+
|
|
14
|
+
const hyperlinker = (text: string, uri: string) =>
|
|
15
|
+
[OSC, '8', SEP, SEP, uri, BEL, text, OSC, '8', SEP, SEP, BEL].join('')
|
|
16
|
+
|
|
17
|
+
function parseVersion(versionString: string): { major: number; minor: number; patch: number } {
|
|
18
|
+
if (/^\d{3,4}$/.test(versionString)) {
|
|
19
|
+
// Env var doesn't always use dots. example: 4601 => 46.1.0
|
|
20
|
+
const m = /(\d{1,2})(\d{2})/.exec(versionString) || []
|
|
21
|
+
return {
|
|
22
|
+
major: 0,
|
|
23
|
+
minor: parseInt(m[1], 10),
|
|
24
|
+
patch: parseInt(m[2], 10),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const versions = (versionString || '').split('.').map((n) => parseInt(n, 10))
|
|
29
|
+
return {
|
|
30
|
+
major: versions[0],
|
|
31
|
+
minor: versions[1],
|
|
32
|
+
patch: versions[2],
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function supportsHyperlink(): boolean {
|
|
37
|
+
const {
|
|
38
|
+
CI,
|
|
39
|
+
FORCE_HYPERLINK,
|
|
40
|
+
NETLIFY,
|
|
41
|
+
TEAMCITY_VERSION,
|
|
42
|
+
TERM_PROGRAM,
|
|
43
|
+
TERM_PROGRAM_VERSION,
|
|
44
|
+
VTE_VERSION,
|
|
45
|
+
VERCEL,
|
|
46
|
+
} = process.env
|
|
47
|
+
|
|
48
|
+
if (FORCE_HYPERLINK) {
|
|
49
|
+
return !(FORCE_HYPERLINK.length > 0 && parseInt(FORCE_HYPERLINK, 10) === 0)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (NETLIFY) return true
|
|
53
|
+
if (process.stdout.isTTY || process.stderr.isTTY) return false
|
|
54
|
+
if (process.platform === 'win32') return false
|
|
55
|
+
if (CI) return false
|
|
56
|
+
if (VERCEL) return false
|
|
57
|
+
if (TEAMCITY_VERSION) return false
|
|
58
|
+
|
|
59
|
+
if (TERM_PROGRAM) {
|
|
60
|
+
const version = parseVersion(TERM_PROGRAM_VERSION || '')
|
|
61
|
+
|
|
62
|
+
switch (TERM_PROGRAM) {
|
|
63
|
+
case 'iTerm.app':
|
|
64
|
+
if (version.major === 3) return version.minor >= 1
|
|
65
|
+
return version.major > 3
|
|
66
|
+
case 'WezTerm':
|
|
67
|
+
return version.major >= 20200620
|
|
68
|
+
case 'vscode':
|
|
69
|
+
return version.major > 1 || (version.major === 1 && version.minor >= 72)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (VTE_VERSION) {
|
|
74
|
+
// 0.50.0 was supposed to support hyperlinks, but throws a segfault
|
|
75
|
+
if (VTE_VERSION === '0.50.0') return false
|
|
76
|
+
const version = parseVersion(VTE_VERSION)
|
|
77
|
+
return version.major > 0 || version.minor >= 50
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const cliHyperlink = (text: string, uri: string) =>
|
|
84
|
+
supportsHyperlink() ? hyperlinker(text, uri) : text
|
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { ApolloLink } from '@apollo/client'
|
|
3
|
+
import type { MeshFetchHTTPInformation } from '@graphql-mesh/plugin-http-details-extensions'
|
|
4
|
+
import { print } from 'graphql'
|
|
5
|
+
import { cliHyperlink } from './lib/hyperlinker'
|
|
3
6
|
|
|
4
7
|
const running = new Map<
|
|
5
8
|
string,
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
endTime: string
|
|
13
|
-
duration: number
|
|
14
|
-
execution: {
|
|
15
|
-
resolvers: {
|
|
16
|
-
path: (string | number)[]
|
|
17
|
-
parentType: string
|
|
18
|
-
fieldName: string
|
|
19
|
-
returnType: string
|
|
20
|
-
startOffset: number
|
|
21
|
-
duration: number
|
|
22
|
-
}[]
|
|
9
|
+
{
|
|
10
|
+
start: Date
|
|
11
|
+
end?: Date
|
|
12
|
+
internalStart?: Date
|
|
13
|
+
operationName: [string, string]
|
|
14
|
+
additional?: [string, string]
|
|
23
15
|
}
|
|
24
|
-
|
|
16
|
+
>()
|
|
25
17
|
|
|
26
18
|
const renderLine = (line: {
|
|
27
19
|
serverStart: number
|
|
28
20
|
requestStart: number
|
|
29
21
|
requestEnd: number
|
|
30
22
|
colDivider: number
|
|
31
|
-
additional: string[]
|
|
23
|
+
additional: (string | [string, string])[]
|
|
32
24
|
}) => {
|
|
33
25
|
const duration = line.requestEnd - line.requestStart
|
|
34
26
|
const serverDuration = duration - line.serverStart
|
|
@@ -88,19 +80,20 @@ export const flushMeasurePerf = () => {
|
|
|
88
80
|
value.operationName,
|
|
89
81
|
// `${duration - (duration - serverStart)}ms`,
|
|
90
82
|
`${duration - serverStart}ms`,
|
|
83
|
+
value.additional ?? '',
|
|
91
84
|
],
|
|
92
85
|
colDivider,
|
|
93
86
|
})
|
|
94
87
|
})
|
|
95
88
|
|
|
96
89
|
const items = [
|
|
97
|
-
['Operation', 'Mesh', 'Timeline'],
|
|
90
|
+
['Operation', 'Mesh', ' Source', 'Timeline'],
|
|
98
91
|
...lines,
|
|
99
92
|
renderLine({
|
|
100
93
|
serverStart: 0,
|
|
101
94
|
requestStart: 0,
|
|
102
95
|
requestEnd: end,
|
|
103
|
-
additional: [`Total time`, `${end}ms
|
|
96
|
+
additional: [`Total time`, `${end}ms`, ''],
|
|
104
97
|
colDivider,
|
|
105
98
|
}),
|
|
106
99
|
]
|
|
@@ -109,16 +102,22 @@ export const flushMeasurePerf = () => {
|
|
|
109
102
|
const colWidths: number[] = Array(items[0].length).fill(0)
|
|
110
103
|
items.forEach((item) => {
|
|
111
104
|
item.forEach((t, index) => {
|
|
112
|
-
colWidths[index] = Math.max(colWidths[index], t.length)
|
|
105
|
+
colWidths[index] = Math.max(colWidths[index], Array.isArray(t) ? t[0].length : t.length)
|
|
113
106
|
})
|
|
114
107
|
})
|
|
115
108
|
|
|
116
109
|
// padd the items to the max length
|
|
117
110
|
items.forEach((item) => {
|
|
118
111
|
item.forEach((_, index) => {
|
|
119
|
-
|
|
120
|
-
index
|
|
121
|
-
|
|
112
|
+
const [str, link] = (
|
|
113
|
+
Array.isArray(item[index]) ? item[index] : [item[index], item[index]]
|
|
114
|
+
) as [string, string]
|
|
115
|
+
|
|
116
|
+
const val = (Array.isArray(item[index]) ? item[index][1] : item[index]) as string
|
|
117
|
+
|
|
118
|
+
const padLength = colWidths[index] + (val.length - str.length)
|
|
119
|
+
|
|
120
|
+
item[index] = `${val.padEnd(padLength, ' ')}${index !== item.length - 1 ? `` : ''}`
|
|
122
121
|
})
|
|
123
122
|
})
|
|
124
123
|
|
|
@@ -147,19 +146,51 @@ export const measurePerformanceLink = new ApolloLink((operation, forward) => {
|
|
|
147
146
|
Object.keys(operation.variables).length > 0 ? `(${JSON.stringify(operation.variables)})` : ''
|
|
148
147
|
const operationString = `${operation.operationName}${vars}`
|
|
149
148
|
|
|
150
|
-
running.set(operationString, {
|
|
149
|
+
running.set(operationString, {
|
|
150
|
+
start: new Date(),
|
|
151
|
+
operationName: [operation.operationName, operation.operationName],
|
|
152
|
+
})
|
|
151
153
|
markTimeout()
|
|
152
154
|
|
|
153
|
-
// console.info(`GraphQL start ${operationString}`)
|
|
154
155
|
return forward(operation).map((data) => {
|
|
155
|
-
const
|
|
156
|
+
const httpDetails: MeshFetchHTTPInformation[] | undefined = data.extensions?.httpDetails
|
|
157
|
+
|
|
158
|
+
let additional = [``, ``] as [string, string]
|
|
159
|
+
if (httpDetails) {
|
|
160
|
+
httpDetails.forEach((d) => {
|
|
161
|
+
const requestUrl = new URL(d.request.url)
|
|
162
|
+
requestUrl.searchParams.delete('extensions')
|
|
163
|
+
const title = `${d.sourceName} ${d.responseTime}ms`
|
|
164
|
+
additional = [
|
|
165
|
+
`${additional[0]} ${title}`,
|
|
166
|
+
`${additional[1]} ${cliHyperlink(title, requestUrl.toString().replace(/\+/g, '%20'))}`,
|
|
167
|
+
]
|
|
168
|
+
})
|
|
169
|
+
}
|
|
156
170
|
|
|
157
171
|
// Called after server responds
|
|
172
|
+
const query = [
|
|
173
|
+
`# Variables: ${JSON.stringify(operation.variables)}`,
|
|
174
|
+
`# Headers: ${JSON.stringify(operation.getContext().headers)}`,
|
|
175
|
+
print(operation.query),
|
|
176
|
+
].join('\n')
|
|
177
|
+
|
|
178
|
+
const meshUrl = new URL(`${import.meta.graphCommerce.canonicalBaseUrl}/api/graphql`)
|
|
179
|
+
meshUrl.searchParams.set('query', query)
|
|
180
|
+
|
|
158
181
|
running.set(operationString, {
|
|
159
|
-
internalStart: tracing ? new Date(tracing.startTime) : undefined,
|
|
160
182
|
start: operation.getContext().measurePerformanceLinkStart as Date,
|
|
161
183
|
end: new Date(),
|
|
162
|
-
operationName: operation.operationName,
|
|
184
|
+
operationName: [operation.operationName, operation.operationName],
|
|
185
|
+
additional,
|
|
186
|
+
// [
|
|
187
|
+
// operation.operationName,
|
|
188
|
+
// cliHyperlink(operation.operationName, meshUrl.toString()),
|
|
189
|
+
// ],
|
|
190
|
+
// additional: [
|
|
191
|
+
// `🔗 ${additional[0]}`,
|
|
192
|
+
// `${cliHyperlink('🔗', meshUrl.toString())} ${additional[1]}`,
|
|
193
|
+
// ],
|
|
163
194
|
})
|
|
164
195
|
|
|
165
196
|
markTimeout()
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/graphql",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "6.0
|
|
5
|
+
"version": "6.1.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"main": "index.ts",
|
|
8
8
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@apollo/client": "^3.7.10",
|
|
17
|
-
"@graphcommerce/graphql-codegen-near-operation-file": "6.0
|
|
18
|
-
"@graphcommerce/graphql-codegen-relay-optimizer-plugin": "6.0
|
|
17
|
+
"@graphcommerce/graphql-codegen-near-operation-file": "6.1.0",
|
|
18
|
+
"@graphcommerce/graphql-codegen-relay-optimizer-plugin": "6.1.0",
|
|
19
19
|
"@graphql-codegen/add": "4.0.1",
|
|
20
20
|
"@graphql-codegen/fragment-matcher": "4.0.1",
|
|
21
21
|
"@graphql-codegen/introspection": "3.0.1",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"graphql": "16.6.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@graphcommerce/eslint-config-pwa": "6.0
|
|
33
|
-
"@graphcommerce/prettier-config-pwa": "6.0
|
|
34
|
-
"@graphcommerce/typescript-config-pwa": "6.0
|
|
32
|
+
"@graphcommerce/eslint-config-pwa": "6.1.0",
|
|
33
|
+
"@graphcommerce/prettier-config-pwa": "6.1.0",
|
|
34
|
+
"@graphcommerce/typescript-config-pwa": "6.1.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": "^18.2.0",
|