@graphcommerce/docs 9.0.0-canary.106 → 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,13 @@
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
+
9
+ ## 9.0.0-canary.107
10
+
3
11
  ## 9.0.0-canary.106
4
12
 
5
13
  ## 9.0.0-canary.105
@@ -152,22 +152,33 @@ cache.
152
152
 
153
153
  The service worker caches:
154
154
 
155
- - [static fonts](https://github.com/shadowwalker/next-pwa/blob/master/cache.js#L28)
156
- - [static images](https://github.com/shadowwalker/next-pwa/blob/master/cache.js#L39)
157
- - [\_next/image](https://github.com/shadowwalker/next-pwa/blob/master/cache.js#L50)
158
- - [js](https://github.com/shadowwalker/next-pwa/blob/master/cache.js#L85)
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/shadowwalker/next-pwa/blob/master/cache.js#L107):
166
- Although it looks like it does, the regex is actually wrong and it does not
167
- cache anything.
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
 
@@ -223,6 +223,10 @@ Provide a value to enable Google Analytics for your store.
223
223
 
224
224
  To override the value for a specific locale, configure in i18n config.
225
225
 
226
+ #### googlePlaystore: [GraphCommerceGooglePlaystoreConfig](#GraphCommerceGooglePlaystoreConfig)
227
+
228
+ To create an assetlinks.json file for the Android app.
229
+
226
230
  #### googleRecaptchaKey: string
227
231
 
228
232
  Google reCAPTCHA site key.
@@ -370,6 +374,18 @@ Issues that this can cause are:
370
374
  - The same package is included multiple times in the bundle, increasing the bundle size.
371
375
  - The Typescript types of the package are not compatible with each other, causing Typescript errors.
372
376
 
377
+ ### GraphCommerceGooglePlaystoreConfig
378
+
379
+ See https://developer.android.com/training/app-links/verify-android-applinks#web-assoc
380
+
381
+ #### packageName: string (required)
382
+
383
+ The package name of the Android app.
384
+
385
+ #### sha256CertificateFingerprint: string (required)
386
+
387
+ The sha256 certificate fingerprint of the Android app.
388
+
373
389
  ### GraphCommercePermissions
374
390
 
375
391
  Permissions input
@@ -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
- ### Requirements
11
+ ### Preparations
12
12
 
13
- - Lixux, MacOS or WSL2
14
- - Install and use node 16/18: `nvm install 16` or `nvm use 16`
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-graphcms/. my-project && rm -rf graphcommerce && cd my-project
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` [?](../framework/config.md#magentostorecode-string)
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.3 or higher - Clean install, a production or a development
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 starting point.
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.s
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.106",
5
+ "version": "9.0.0-canary.108",
6
6
  "sideEffects": true,
7
7
  "peerDependencies": {
8
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.106"
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