@graphcommerce/docs 9.0.0-canary.107 → 9.0.0-canary.108
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
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 9.0.0-canary.108
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2439](https://github.com/graphcommerce-org/graphcommerce/pull/2439) [`6061226`](https://github.com/graphcommerce-org/graphcommerce/commit/60612265466e4c508a2d3f478ff679251e7819de) - Moved to serwist for service workers ([@paales](https://github.com/paales))
|
|
8
|
+
|
|
3
9
|
## 9.0.0-canary.107
|
|
4
10
|
|
|
5
11
|
## 9.0.0-canary.106
|
package/framework/caching.md
CHANGED
|
@@ -152,22 +152,33 @@ cache.
|
|
|
152
152
|
|
|
153
153
|
The service worker caches:
|
|
154
154
|
|
|
155
|
-
- [static fonts](https://github.com/
|
|
156
|
-
|
|
157
|
-
- [
|
|
158
|
-
|
|
155
|
+
- [static fonts](https://github.com/serwist/serwist/blob/main/packages/next/src/index.worker.ts#L27):
|
|
156
|
+
Google fonts and webfonts with StaleWhileRevalidate strategy
|
|
157
|
+
- [static images](https://github.com/serwist/serwist/blob/main/packages/next/src/index.worker.ts#L64):
|
|
158
|
+
jpg, jpeg, gif, png, svg, ico, webp with StaleWhileRevalidate strategy
|
|
159
|
+
- [\_next/image](https://github.com/graphcommerce-org/graphcommerce/blob/main/packages/service-worker/runtimeCaching.ts#L6):
|
|
160
|
+
Custom implementation with StaleWhileRevalidate and nextImagePlugin
|
|
161
|
+
- js and css files: Only for files outside of `_next/static` with
|
|
162
|
+
StaleWhileRevalidate strategy
|
|
163
|
+
|
|
164
|
+
Notable differences from previous implementation:
|
|
165
|
+
|
|
166
|
+
- All `_next/static` files (js, css) are excluded from runtime caching as they
|
|
167
|
+
are handled by the precache mechanism
|
|
168
|
+
- Cross-origin requests use NetworkOnly strategy instead of NetworkFirst
|
|
169
|
+
- Image caching has been optimized with custom configuration for better
|
|
170
|
+
performance
|
|
159
171
|
|
|
160
172
|
Note: When a new deployment is made, the service worker is updated. This means
|
|
161
173
|
that all previous caches are cleared and new caches are created.
|
|
162
174
|
|
|
163
175
|
It does not cache:
|
|
164
176
|
|
|
165
|
-
- [\_next/data](https://github.com/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- [pages](https://github.com/shadowwalker/next-pwa/blob/master/cache.js#L152)
|
|
177
|
+
- [\_next/data](https://github.com/ducanh-99/serwist/blob/main/packages/next/src/index.worker.ts#L137):
|
|
178
|
+
Uses NetworkFirst strategy to ensure fresh data
|
|
179
|
+
- [pages](https://github.com/ducanh-99/serwist/blob/main/packages/next/src/index.worker.ts#L152):
|
|
169
180
|
Uses NetworkFirst strategy, which means it will always try to fetch the
|
|
170
|
-
resource from the network first, and only if that fails it will use the cache
|
|
181
|
+
resource from the network first, and only if that fails it will use the cache
|
|
171
182
|
|
|
172
183
|
## Cache invalidation limitations
|
|
173
184
|
|
|
@@ -8,10 +8,10 @@ metaTitle: Getting started with GraphCommerce
|
|
|
8
8
|
In this guide, you will set up a GraphCommerce app locally, allowing you to
|
|
9
9
|
start building.
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Preparations
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
- Install and use node
|
|
13
|
+
- MacOS, Windows with WSL2 or Linux
|
|
14
|
+
- Install and use node 20: `nvm install 20` or `nvm use 20`
|
|
15
15
|
- Install yarn: `corepack enable`
|
|
16
16
|
|
|
17
17
|
## Step 1: Create a GraphCommerce app
|
|
@@ -26,19 +26,34 @@ mkdir my-project
|
|
|
26
26
|
# Create project folder
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
There are a few starting points to choose from with or without Hygraph:
|
|
30
|
+
|
|
31
|
+
Option 1: Only Magento Open Source:
|
|
32
|
+
|
|
29
33
|
```bash
|
|
30
|
-
cp -R graphcommerce/examples/magento-
|
|
31
|
-
# Copy example, delete repo, navigate to project folder
|
|
34
|
+
cp -R graphcommerce/examples/magento-magento-open-source/. my-project && cd my-project
|
|
32
35
|
```
|
|
33
36
|
|
|
37
|
+
Option 2: Magento Open Source + Hygraph:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cp -R graphcommerce/examples/magento-graphcms/. my-project && cd my-project
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Option 3: Adobe Commerce:
|
|
44
|
+
|
|
45
|
+
Please contact us for more information to get access to the Adobe Commerce
|
|
46
|
+
starting point.
|
|
47
|
+
|
|
34
48
|
## Step 2: Configure API keys (optional)
|
|
35
49
|
|
|
36
50
|
Duplicate and rename the configuration example file to:
|
|
37
51
|
`graphcommerce.config.js` and configure the following:
|
|
38
52
|
|
|
39
|
-
- `magentoEndpoint` [?](../framework/config.md#magentoendpoint-string)
|
|
40
|
-
- `hygraphEndpoint` [?](../framework/config.md#hygraphendpoint-string)
|
|
41
|
-
- `magentoStoreCode`
|
|
53
|
+
- `magentoEndpoint` [?](../framework/config.md#magentoendpoint-string-required)
|
|
54
|
+
- `hygraphEndpoint` [?](../framework/config.md#hygraphendpoint-string-required)
|
|
55
|
+
- `magentoStoreCode`
|
|
56
|
+
[?](../framework/config.md#magentostorecode-string-required)
|
|
42
57
|
|
|
43
58
|
> magentoStoreCode
|
|
44
59
|
>
|
|
@@ -55,11 +70,12 @@ Duplicate and rename the configuration example file to:
|
|
|
55
70
|
|
|
56
71
|
### Requirements
|
|
57
72
|
|
|
58
|
-
- Magento version 2.4.
|
|
59
|
-
environment
|
|
73
|
+
- Magento version 2.4.5 or higher - Clean install, a production or a development
|
|
74
|
+
environment (technically 2.4.3 and 2.4.4 also work, but in practice important
|
|
75
|
+
bugfixes have been made in the latest versions.)
|
|
60
76
|
- Hygraph - A project with the required schema.
|
|
61
77
|
[Clone ↗](https://app.hygraph.com/clone/caddaa93cfa9436a9e76ae9c0f34d257?name=GraphCommerce%20Demo)
|
|
62
|
-
the schema as your
|
|
78
|
+
the schema as your starwting point.
|
|
63
79
|
|
|
64
80
|
## Step 3: Start the app
|
|
65
81
|
|
|
@@ -88,7 +88,7 @@ persisted, except for pruned data (see
|
|
|
88
88
|
|
|
89
89
|
Since this phase is late, do not use the result of non-session specific queries
|
|
90
90
|
for the initial render. This also causes rerenders of the components causing all
|
|
91
|
-
vitals to be affected.
|
|
91
|
+
vitals to be affected.
|
|
92
92
|
|
|
93
93
|
Solution: Move data fetching to the `getStaticProps` or `getServerSideProps`
|
|
94
94
|
functions. That can be a bit unergonomic, in that case move the data fetching
|
|
@@ -107,6 +107,74 @@ and it's
|
|
|
107
107
|
and
|
|
108
108
|
[mesh configuration plugin](https://github.com/graphcommerce-org/graphcommerce/blob/canary/packages/magento-graphql/plugins/meshConfigAttrValue.ts).
|
|
109
109
|
|
|
110
|
+
## Prevent components outside of the viewport from unnecessarily hydrating
|
|
111
|
+
|
|
112
|
+
To keep the Hydration phase as short as possible, it's a good idea to postpone
|
|
113
|
+
the hydration of (heavy) components that are outside of the viewport until they
|
|
114
|
+
are needed. By using `<LazyHydrate>`, the component can be hydrated either
|
|
115
|
+
manually, by setting the `hydrated` prop to true or automatically by the
|
|
116
|
+
IntersectionObserver inside `<LazyHydrate>` (as soon as the component comes into
|
|
117
|
+
view). It is recommended to set an estimated height value on the `height` prop.
|
|
118
|
+
This will reserver space for the component, when the page is loaded clientside.
|
|
119
|
+
This is to prevent multiple `LazyHydrate` components below each other from
|
|
120
|
+
intersecting all at once (as they do not have any HTML, and thus any height,
|
|
121
|
+
when loaded clientside). This height does not need to be exact.
|
|
122
|
+
|
|
123
|
+
The IntersectionObserver method of hydrating should never be used for components
|
|
124
|
+
that are inside the viewport on pageload, as it requires JS and is asynchronous.
|
|
125
|
+
When items are rendered in a loop and the first few items are inside the
|
|
126
|
+
viewport, these should be set to `hydrated={true}` based on the index of the
|
|
127
|
+
loop.
|
|
128
|
+
|
|
129
|
+
Example 1:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { LazyHydrate } from '@graphcommerce/next-ui'
|
|
133
|
+
|
|
134
|
+
function MyLayout() {
|
|
135
|
+
return (
|
|
136
|
+
<MyComponentAboveTheFold>
|
|
137
|
+
Immediately hydrated
|
|
138
|
+
</MyComponentAboveTheFold>
|
|
139
|
+
|
|
140
|
+
<LazyHydrate hydrated={true}>
|
|
141
|
+
<MyComponentAboveTheFold>
|
|
142
|
+
Immediately hydrated
|
|
143
|
+
</MyComponentAboveTheFold>
|
|
144
|
+
</<LazyHydrate>
|
|
145
|
+
|
|
146
|
+
<LazyHydrate height={500}>
|
|
147
|
+
<MyExpensiveComponentBelowTheFold>
|
|
148
|
+
Only hydrated when scrolled into view
|
|
149
|
+
</MyExpensiveComponentBelowTheFold>
|
|
150
|
+
</LazyHydrate>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Example 2:
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
export function MyItems(props) {
|
|
159
|
+
const { items, loadingEager = 2 } = props
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<>
|
|
163
|
+
{items.map((item, index) => (
|
|
164
|
+
// The first two items are hydrated immediately. Any items after that are hydrated on intersection
|
|
165
|
+
<LazyHydrate
|
|
166
|
+
key={item.id}
|
|
167
|
+
hydrated={index < loadingEager ? true : undefined}
|
|
168
|
+
height={500}
|
|
169
|
+
>
|
|
170
|
+
<MyComponent {...item} />
|
|
171
|
+
</LazyHydrate>
|
|
172
|
+
))}
|
|
173
|
+
</>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
110
178
|
## Conditionally render on mobile/desktop
|
|
111
179
|
|
|
112
180
|
TLDR: Use the `<MediaQuery>` component instead of useMediaQuery or CSS
|
|
@@ -193,3 +261,95 @@ function MyLayout() {
|
|
|
193
261
|
)
|
|
194
262
|
}
|
|
195
263
|
```
|
|
264
|
+
|
|
265
|
+
## Use Context + useState cautiously
|
|
266
|
+
|
|
267
|
+
Contexts + useState should be used cautiously. When the state updates, it causes
|
|
268
|
+
ALL components within the context provider to rerender, not just the components
|
|
269
|
+
that use the context. When wrapping a lot of components inside a context, this
|
|
270
|
+
can become very expensive.
|
|
271
|
+
|
|
272
|
+
Solution for state that involves query data: Use Apollo Client cache, by using
|
|
273
|
+
`useQuery` for data that is already fetched on the server and cached by Apollo.
|
|
274
|
+
|
|
275
|
+
Solution for local state: use
|
|
276
|
+
[Apollo Reactive variables](https://www.apollographql.com/docs/react/local-state/reactive-variables)
|
|
277
|
+
|
|
278
|
+
## Image resizing
|
|
279
|
+
|
|
280
|
+
When using the Image component, the sizes prop should be set correctly so no
|
|
281
|
+
unnecessarily large images are served. The prop accepts either a string (vw, px,
|
|
282
|
+
calc(), etc) or an object with breakpoints and a string value. See the
|
|
283
|
+
[prop type](https://github.com/graphcommerce-org/graphcommerce/blob/canary/packages/image/components/Image.tsx#L176-L185)
|
|
284
|
+
for all available options.
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
<Image
|
|
290
|
+
layout='fill'
|
|
291
|
+
alt={item.label}
|
|
292
|
+
src={item.url}
|
|
293
|
+
sizes={{
|
|
294
|
+
0: '100vw',
|
|
295
|
+
[theme.breakpoints.values.md]: '50vw',
|
|
296
|
+
}}
|
|
297
|
+
/>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Preventing a query waterfall
|
|
301
|
+
|
|
302
|
+
When querying inside `getStaticProps`, only use `await` when the data is
|
|
303
|
+
required for something else inside `getStaticProps`. Otherwise it should be
|
|
304
|
+
awaited in the return statement. When a query is awaited immediately, it halts
|
|
305
|
+
the code at that point until that query completes. Meaning any queries called
|
|
306
|
+
after that will be called in serial. Awaiting all queries in the return
|
|
307
|
+
statement allows the queries to be called in parallel.
|
|
308
|
+
|
|
309
|
+
Example:
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
// Bad, because each query needs to wait until the previous one is completed entirely before being fired
|
|
313
|
+
export const getStaticProps: GetPageStaticProps = async (context) => {
|
|
314
|
+
// Query takes 100ms - code is halted until it finishes
|
|
315
|
+
const {data: queryOne} = await staticClient.query({ query: queryOneDocument })
|
|
316
|
+
// Query takes 100ms - code is halted until it finishes
|
|
317
|
+
const {data: queryTwo} = await staticClient.query({ query: queryTwoDocument })
|
|
318
|
+
// Query takes 100ms - code is halted until it finishes
|
|
319
|
+
const {data: queryThree} = await staticClient.query({ query: queryThreeDocument })
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
props: {
|
|
324
|
+
...queryOne
|
|
325
|
+
...queryTwo
|
|
326
|
+
...queryThree
|
|
327
|
+
// Total wait time 300ms
|
|
328
|
+
},
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
// Good, because each query is fired in parallel and only awaited when each query is already running in the background
|
|
335
|
+
export const getStaticProps: GetPageStaticProps = async (context) => {
|
|
336
|
+
// Query takes 100ms - but it runs in the background, code continues execution
|
|
337
|
+
const queryOne = staticClient.query({ query: queryOneDocument })
|
|
338
|
+
// Query takes 100ms - but it runs in the background, code continues execution
|
|
339
|
+
const queryTwo = staticClient.query({ query: queryTwoDocument })
|
|
340
|
+
// Query takes 100ms - but it runs in the background, code continues execution
|
|
341
|
+
const queryThree = staticClient.query({ query: queryThreeDocument })
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
props: {
|
|
345
|
+
// Awaits query (100ms)
|
|
346
|
+
...(await queryOne).data
|
|
347
|
+
// Awaits query, already finished in the background (0ms)
|
|
348
|
+
...(await queryTwo).data
|
|
349
|
+
// Awaits query, already finished in the background (0ms)
|
|
350
|
+
...(await queryThree).data
|
|
351
|
+
// Total wait time 100ms
|
|
352
|
+
},
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"name": "@graphcommerce/docs",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/docs",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce/docs",
|
|
5
|
-
"version": "9.0.0-canary.
|
|
5
|
+
"version": "9.0.0-canary.108",
|
|
6
6
|
"sideEffects": true,
|
|
7
7
|
"peerDependencies": {
|
|
8
|
-
"@graphcommerce/prettier-config-pwa": "^9.0.0-canary.
|
|
8
|
+
"@graphcommerce/prettier-config-pwa": "^9.0.0-canary.108"
|
|
9
9
|
},
|
|
10
10
|
"prettier": "@graphcommerce/prettier-config-pwa"
|
|
11
11
|
}
|
|
@@ -5,6 +5,9 @@ steps. Please follow the regular [upgrade steps first](./readme.md).
|
|
|
5
5
|
|
|
6
6
|
1. ReactPlugin TypeScript definition is removed.
|
|
7
7
|
2. Locales now require an explicit configuration.
|
|
8
|
+
3. `@graphcommerce/graphcms-ui` is now `@graphcommerce/hygraph-ui`
|
|
9
|
+
4. `@ducanh2912/next-pwa` replaced by `serwist`
|
|
10
|
+
5. `next-sitemap` replaced by custom implementation
|
|
8
11
|
|
|
9
12
|
## 1. ReactPlugin TypeScript definition is removed
|
|
10
13
|
|
|
@@ -56,3 +59,14 @@ const config = {
|
|
|
56
59
|
3. `@graphcommerce/graphcms-ui` is now `@graphcommerce/hygraph-ui`
|
|
57
60
|
|
|
58
61
|
Replace all `@graphcommerce/graphcms-ui` with `@graphcommerce/hygraph-ui`.
|
|
62
|
+
|
|
63
|
+
4. `@ducanh2912/next-pwa` replaced by `serwist`
|
|
64
|
+
|
|
65
|
+
Any customizations made to the service worker should
|
|
66
|
+
|
|
67
|
+
5. `next-sitemap` replaced by custom implementation.
|
|
68
|
+
|
|
69
|
+
- pages/robots.txt.tsx
|
|
70
|
+
- pages/sitemap/categories.xml.tsx
|
|
71
|
+
- pages/sitemap/content.xml.tsx
|
|
72
|
+
- pages/sitemap/products.xml.tsx
|