@shopify/cli 3.72.2 → 3.73.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/dist/assets/hydrogen/starter/CHANGELOG.md +814 -0
- package/dist/assets/hydrogen/starter/app/components/Aside.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/PaginatedResourceSection.tsx +3 -4
- package/dist/assets/hydrogen/starter/app/components/ProductForm.tsx +113 -44
- package/dist/assets/hydrogen/starter/app/components/SearchResults.tsx +8 -3
- package/dist/assets/hydrogen/starter/app/components/SearchResultsPredictive.tsx +6 -5
- package/dist/assets/hydrogen/starter/app/lib/variants.ts +3 -3
- package/dist/assets/hydrogen/starter/app/routes/account_.logout.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +9 -16
- package/dist/assets/hydrogen/starter/app/routes/collections.$handle.tsx +1 -10
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +1 -10
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +50 -119
- package/dist/assets/hydrogen/starter/app/routes/search.tsx +42 -38
- package/dist/assets/hydrogen/starter/app/styles/app.css +25 -1
- package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +23 -20
- package/dist/assets/hydrogen/starter/guides/search/search.md +27 -25
- package/dist/assets/hydrogen/starter/package.json +3 -3
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +177 -194
- package/dist/assets/hydrogen/tailwind/tailwind.css +1 -1
- package/dist/{chokidar-OESTCX4H.js → chokidar-5LLC6S6D.js} +47 -90
- package/dist/{chunk-VSLR7ET4.js → chunk-25IMI7TH.js} +8 -46
- package/dist/{chunk-NCKQIOV4.js → chunk-3HBRMIPY.js} +28 -50
- package/dist/{chunk-4HTVLK2H.js → chunk-3OXCI3HX.js} +1402 -1989
- package/dist/{chunk-2YCRDHPC.js → chunk-5OFJTURZ.js} +4 -4
- package/dist/{chunk-TAKO7LSJ.js → chunk-65GSOZHL.js} +7 -7
- package/dist/{chunk-6IUL3QZW.js → chunk-66HLUVKV.js} +4 -4
- package/dist/{chunk-N2V4IFX3.js → chunk-6PEBJVBW.js} +3 -3
- package/dist/{chunk-XVNW332R.js → chunk-75LV6AQS.js} +6 -10
- package/dist/{chunk-QXIIXX7G.js → chunk-7RKRCUFA.js} +16518 -24140
- package/dist/{chunk-ZESD7DR7.js → chunk-AFPOP3K5.js} +67 -104
- package/dist/{chunk-2HGYYNE5.js → chunk-B5EXYCV3.js} +5 -9
- package/dist/{chunk-NB4NLOEJ.js → chunk-BUFIEXZ5.js} +11 -20
- package/dist/{chunk-YXJHYEP7.js → chunk-CEIZT2W3.js} +4 -4
- package/dist/{chunk-522OB3EU.js → chunk-CFIKVUNW.js} +2 -2
- package/dist/{chunk-KYB6A4PE.js → chunk-CRHXI6PS.js} +13 -23
- package/dist/{chunk-PQQTBTYM.js → chunk-ELTOJBOJ.js} +4 -5
- package/dist/{chunk-NUP5TATA.js → chunk-EZQWZ57B.js} +2 -2
- package/dist/{chunk-YKUYPSCY.js → chunk-F7D333WQ.js} +3 -3
- package/dist/{chunk-UBB7JKND.js → chunk-G2ZZKGSV.js} +2 -2
- package/dist/{chunk-CBBS4CV7.js → chunk-G5R6YD27.js} +8 -13
- package/dist/{chunk-RCRRAFH7.js → chunk-GDLROW57.js} +3 -3
- package/dist/{chunk-KMZ5JSGS.js → chunk-I25PGLBO.js} +3 -3
- package/dist/{chunk-OXKHBIW7.js → chunk-IG5SOACB.js} +29 -34
- package/dist/{chunk-UIRMJZRW.js → chunk-IRHYYIN7.js} +4 -4
- package/dist/{chunk-OWLPHMUA.js → chunk-J673ZU5S.js} +4 -4
- package/dist/{chunk-HYGCZ6GV.js → chunk-JORKLY7M.js} +68 -49
- package/dist/{chunk-K6Y4FYT5.js → chunk-K7HGDAI4.js} +17 -20
- package/dist/{chunk-I6R52HNI.js → chunk-KF2D6QHZ.js} +39 -68
- package/dist/{chunk-KGKTCQ7H.js → chunk-KMWARALD.js} +5 -5
- package/dist/{chunk-VWNWE4HG.js → chunk-KTNFE44J.js} +110 -83
- package/dist/{chunk-BYPQXSAL.js → chunk-KUM3DVPF.js} +17 -13
- package/dist/{chunk-K7B4JJLF.js → chunk-KZBL6BQ7.js} +4 -4
- package/dist/{chunk-WNDN5FAY.js → chunk-MHUINF7I.js} +3 -3
- package/dist/{chunk-L2J5VM7R.js → chunk-NFQLKURK.js} +41 -68
- package/dist/{chunk-KCI6QCAV.js → chunk-O77L7CCL.js} +4 -4
- package/dist/{chunk-SNOECVP4.js → chunk-OAZFIMJ3.js} +2 -2
- package/dist/{chunk-GVNIHXMX.js → chunk-OE3IXTC5.js} +38 -60
- package/dist/{chunk-ECWFBV2F.js → chunk-ONOLOXLM.js} +5 -5
- package/dist/{chunk-POZ5MGPT.js → chunk-PKR7KJ6P.js} +2 -3
- package/dist/{chunk-JDM5VOXB.js → chunk-PRWEHR2C.js} +3 -3
- package/dist/{chunk-SO2RZ6TZ.js → chunk-QNK2EAZ3.js} +5 -5
- package/dist/{chunk-E37RRDIH.js → chunk-RCA7PFH4.js} +4 -4
- package/dist/{chunk-GKEFW755.js → chunk-RK7JAMCI.js} +6 -6
- package/dist/{chunk-HMUOOT55.js → chunk-SANP6FPA.js} +6 -6
- package/dist/{chunk-OJOHMVV7.js → chunk-SBPFWO4S.js} +294 -448
- package/dist/{chunk-O5K4AU7Q.js → chunk-SHWOPMLQ.js} +3 -4
- package/dist/{chunk-NE43V3EI.js → chunk-SUUVDRTQ.js} +6 -7
- package/dist/{chunk-VJ7TIVX7.js → chunk-TEHNKBLD.js} +6 -7
- package/dist/{chunk-KVEY52WG.js → chunk-VPNXQGG6.js} +4 -4
- package/dist/{chunk-NXHZX3WR.js → chunk-X5FJXK25.js} +9 -9
- package/dist/{chunk-PMUQTGZJ.js → chunk-X7YTIMNN.js} +4 -6
- package/dist/{chunk-UIAIRQSP.js → chunk-XAGT2UNE.js} +3 -3
- package/dist/{chunk-7Q3MMWAC.js → chunk-XE5EOEBL.js} +2 -2
- package/dist/{chunk-PKJLXLTR.js → chunk-YP7WU5EU.js} +5 -5
- package/dist/{chunk-QDPQB6WU.js → chunk-YPTEMDFR.js} +5 -5
- package/dist/{chunk-KWLJTNRE.js → chunk-ZENVITME.js} +4 -4
- package/dist/{chunk-HSTSRNLJ.js → chunk-ZX3L2JKV.js} +64 -86
- package/dist/cli/commands/auth/logout.js +28 -28
- package/dist/cli/commands/auth/logout.test.js +30 -30
- package/dist/cli/commands/cache/clear.js +27 -27
- package/dist/cli/commands/debug/command-flags.js +27 -27
- package/dist/cli/commands/docs/generate.js +27 -27
- package/dist/cli/commands/docs/generate.test.js +28 -28
- package/dist/cli/commands/help.js +27 -27
- package/dist/cli/commands/kitchen-sink/async.js +28 -28
- package/dist/cli/commands/kitchen-sink/async.test.js +29 -29
- package/dist/cli/commands/kitchen-sink/index.js +30 -30
- package/dist/cli/commands/kitchen-sink/index.test.js +31 -31
- package/dist/cli/commands/kitchen-sink/prompts.js +28 -28
- package/dist/cli/commands/kitchen-sink/prompts.test.js +29 -29
- package/dist/cli/commands/kitchen-sink/static.js +28 -28
- package/dist/cli/commands/kitchen-sink/static.test.js +29 -29
- package/dist/cli/commands/notifications/generate.js +28 -28
- package/dist/cli/commands/notifications/list.js +28 -28
- package/dist/cli/commands/search.js +28 -28
- package/dist/cli/commands/upgrade.js +28 -28
- package/dist/cli/commands/upgrade.test.js +3 -3
- package/dist/cli/commands/version.js +28 -28
- package/dist/cli/commands/version.test.js +29 -29
- package/dist/cli/services/commands/notifications.js +21 -21
- package/dist/cli/services/commands/search.js +15 -15
- package/dist/cli/services/commands/search.test.js +16 -16
- package/dist/cli/services/commands/version.js +16 -16
- package/dist/cli/services/commands/version.test.js +18 -18
- package/dist/cli/services/kitchen-sink/async.js +15 -15
- package/dist/cli/services/kitchen-sink/prompts.js +15 -15
- package/dist/cli/services/kitchen-sink/static.js +15 -15
- package/dist/cli/services/upgrade.js +17 -17
- package/dist/cli/services/upgrade.test.js +20 -20
- package/dist/configs/all.yml +12 -0
- package/dist/configs/recommended.yml +15 -0
- package/dist/configs/theme-app-extension.yml +3 -0
- package/dist/{custom-oclif-loader-G2DAJL7B.js → custom-oclif-loader-V3IB4SYZ.js} +15 -15
- package/dist/data/latest.json +1 -1
- package/dist/data/manifest_theme.json +1 -0
- package/dist/data/preset.json +66 -0
- package/dist/data/preset_blocks.json +20 -13
- package/dist/data/section.json +1 -15
- package/dist/data/setting.json +1 -1
- package/dist/data/theme_block.json +1 -15
- package/dist/{del-K5ZJEWTD.js → del-P2RS6GN2.js} +9 -9
- package/dist/{devtools-KYKGATNX.js → devtools-K7FXBBFZ.js} +3 -3
- package/dist/error-handler-WK3AZ7A2.js +38 -0
- package/dist/hooks/postrun.js +22 -22
- package/dist/hooks/prerun.js +22 -22
- package/dist/{http-proxy-GGTVQ6CU.js → http-proxy-FXWKYHZ3.js} +14 -24
- package/dist/index.js +7228 -7320
- package/dist/lib-JVEIEXYB.js +6 -0
- package/dist/lib-QZGSY5YB.js +13 -0
- package/dist/{local-Q5ZG2NHX.js → local-3ERK45M5.js} +15 -15
- package/dist/{magic-string.es-3RXPUXZF.js → magic-string.es-PJMYOE6F.js} +49 -96
- package/dist/{morph-SEECJQ2W.js → morph-OSHCID2F.js} +261 -347
- package/dist/{multipart-parser-QKUAJJP5.js → multipart-parser-WSNBP656.js} +8 -7
- package/dist/{node-S6CM3NTX.js → node-2KLEBSMO.js} +31 -31
- package/dist/{node-package-manager-GUY5IO3W.js → node-package-manager-QIM24GB3.js} +19 -17
- package/dist/{npa-RLWNZ3BM.js → npa-TM76BGG3.js} +10 -16
- package/dist/{open-MZGVNFZO.js → open-BHIF7E3E.js} +3 -3
- package/dist/out-JR4DWQ2G.js +7 -0
- package/dist/{path-NDLRQPLA.js → path-2HZUSAGR.js} +3 -3
- package/dist/{source-map-7AAPWPHZ.js → source-map-QCVC46UY.js} +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{ui-AWSBLSD4.js → ui-5AHG256I.js} +15 -15
- package/dist/{workerd-3HGLHQET.js → workerd-MSNALKI2.js} +30 -30
- package/oclif.manifest.json +81 -1
- package/package.json +8 -8
- package/dist/error-handler-6HCFKLTC.js +0 -38
- package/dist/lib-PPXZBVZX.js +0 -6
- package/dist/lib-XYCLX35G.js +0 -13
- package/dist/out-MHEKZJWS.js +0 -7
|
@@ -1,5 +1,819 @@
|
|
|
1
1
|
# skeleton
|
|
2
2
|
|
|
3
|
+
## 2024.10.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Remove initial redirect from product display page ([#2643](https://github.com/Shopify/hydrogen/pull/2643)) by [@scottdixon](https://github.com/scottdixon)
|
|
8
|
+
|
|
9
|
+
- Optional updates for the product route and product form to handle combined listing and 2000 variant limit. ([#2659](https://github.com/Shopify/hydrogen/pull/2659)) by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
10
|
+
|
|
11
|
+
1. Update your SFAPI product query to bring in the new query fields:
|
|
12
|
+
|
|
13
|
+
```diff
|
|
14
|
+
const PRODUCT_FRAGMENT = `#graphql
|
|
15
|
+
fragment Product on Product {
|
|
16
|
+
id
|
|
17
|
+
title
|
|
18
|
+
vendor
|
|
19
|
+
handle
|
|
20
|
+
descriptionHtml
|
|
21
|
+
description
|
|
22
|
+
+ encodedVariantExistence
|
|
23
|
+
+ encodedVariantAvailability
|
|
24
|
+
options {
|
|
25
|
+
name
|
|
26
|
+
optionValues {
|
|
27
|
+
name
|
|
28
|
+
+ firstSelectableVariant {
|
|
29
|
+
+ ...ProductVariant
|
|
30
|
+
+ }
|
|
31
|
+
+ swatch {
|
|
32
|
+
+ color
|
|
33
|
+
+ image {
|
|
34
|
+
+ previewImage {
|
|
35
|
+
+ url
|
|
36
|
+
+ }
|
|
37
|
+
+ }
|
|
38
|
+
+ }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
- selectedVariant: selectedOrFirstAvailableVariant(selectedOptions: $selectedOptions, ignoreUnknownOptions: true, caseInsensitiveMatch: true) {
|
|
42
|
+
+ selectedOrFirstAvailableVariant(selectedOptions: $selectedOptions, ignoreUnknownOptions: true, caseInsensitiveMatch: true) {
|
|
43
|
+
+ ...ProductVariant
|
|
44
|
+
+ }
|
|
45
|
+
+ adjacentVariants (selectedOptions: $selectedOptions) {
|
|
46
|
+
+ ...ProductVariant
|
|
47
|
+
+ }
|
|
48
|
+
- variants(first: 1) {
|
|
49
|
+
- nodes {
|
|
50
|
+
- ...ProductVariant
|
|
51
|
+
- }
|
|
52
|
+
- }
|
|
53
|
+
seo {
|
|
54
|
+
description
|
|
55
|
+
title
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
${PRODUCT_VARIANT_FRAGMENT}
|
|
59
|
+
` as const;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
2. Update `loadDeferredData` function. We no longer need to load in all the variants. You can also remove `VARIANTS_QUERY` variable.
|
|
63
|
+
|
|
64
|
+
```diff
|
|
65
|
+
function loadDeferredData({context, params}: LoaderFunctionArgs) {
|
|
66
|
+
+ // Put any API calls that is not critical to be available on first page render
|
|
67
|
+
+ // For example: product reviews, product recommendations, social feeds.
|
|
68
|
+
- // In order to show which variants are available in the UI, we need to query
|
|
69
|
+
- // all of them. But there might be a *lot*, so instead separate the variants
|
|
70
|
+
- // into it's own separate query that is deferred. So there's a brief moment
|
|
71
|
+
- // where variant options might show as available when they're not, but after
|
|
72
|
+
- // this deferred query resolves, the UI will update.
|
|
73
|
+
- const variants = context.storefront
|
|
74
|
+
- .query(VARIANTS_QUERY, {
|
|
75
|
+
- variables: {handle: params.handle!},
|
|
76
|
+
- })
|
|
77
|
+
- .catch((error) => {
|
|
78
|
+
- // Log query errors, but don't throw them so the page can still render
|
|
79
|
+
- console.error(error);
|
|
80
|
+
- return null;
|
|
81
|
+
- });
|
|
82
|
+
|
|
83
|
+
+ return {}
|
|
84
|
+
- return {
|
|
85
|
+
- variants,
|
|
86
|
+
- };
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. Remove the redirect logic in the `loadCriticalData` function and completely remove `redirectToFirstVariant` function
|
|
91
|
+
|
|
92
|
+
```diff
|
|
93
|
+
async function loadCriticalData({
|
|
94
|
+
context,
|
|
95
|
+
params,
|
|
96
|
+
request,
|
|
97
|
+
}: LoaderFunctionArgs) {
|
|
98
|
+
const {handle} = params;
|
|
99
|
+
const {storefront} = context;
|
|
100
|
+
if (!handle) {
|
|
101
|
+
throw new Error('Expected product handle to be defined');
|
|
102
|
+
}
|
|
103
|
+
const [{product}] = await Promise.all([
|
|
104
|
+
storefront.query(PRODUCT_QUERY, {
|
|
105
|
+
variables: {handle, selectedOptions: getSelectedProductOptions(request)},
|
|
106
|
+
}),
|
|
107
|
+
// Add other queries here, so that they are loaded in parallel
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
if (!product?.id) {
|
|
111
|
+
throw new Response(null, {status: 404});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
- const firstVariant = product.variants.nodes[0];
|
|
115
|
+
- const firstVariantIsDefault = Boolean(
|
|
116
|
+
- firstVariant.selectedOptions.find(
|
|
117
|
+
- (option: SelectedOption) =>
|
|
118
|
+
- option.name === 'Title' && option.value === 'Default Title',
|
|
119
|
+
- ),
|
|
120
|
+
- );
|
|
121
|
+
|
|
122
|
+
- if (firstVariantIsDefault) {
|
|
123
|
+
- product.selectedVariant = firstVariant;
|
|
124
|
+
- } else {
|
|
125
|
+
- // if no selected variant was returned from the selected options,
|
|
126
|
+
- // we redirect to the first variant's url with it's selected options applied
|
|
127
|
+
- if (!product.selectedVariant) {
|
|
128
|
+
- throw redirectToFirstVariant({product, request});
|
|
129
|
+
- }
|
|
130
|
+
- }
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
product,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
- function redirectToFirstVariant({
|
|
140
|
+
- product,
|
|
141
|
+
- request,
|
|
142
|
+
- }: {
|
|
143
|
+
- product: ProductFragment;
|
|
144
|
+
- request: Request;
|
|
145
|
+
- }) {
|
|
146
|
+
- ...
|
|
147
|
+
- }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
4. Update the `Product` component to use the new data fields.
|
|
151
|
+
|
|
152
|
+
```diff
|
|
153
|
+
import {
|
|
154
|
+
getSelectedProductOptions,
|
|
155
|
+
Analytics,
|
|
156
|
+
useOptimisticVariant,
|
|
157
|
+
+ getAdjacentAndFirstAvailableVariants,
|
|
158
|
+
} from '@shopify/hydrogen';
|
|
159
|
+
|
|
160
|
+
export default function Product() {
|
|
161
|
+
+ const {product} = useLoaderData<typeof loader>();
|
|
162
|
+
- const {product, variants} = useLoaderData<typeof loader>();
|
|
163
|
+
|
|
164
|
+
+ // Optimistically selects a variant with given available variant information
|
|
165
|
+
+ const selectedVariant = useOptimisticVariant(
|
|
166
|
+
+ product.selectedOrFirstAvailableVariant,
|
|
167
|
+
+ getAdjacentAndFirstAvailableVariants(product),
|
|
168
|
+
+ );
|
|
169
|
+
- const selectedVariant = useOptimisticVariant(
|
|
170
|
+
- product.selectedVariant,
|
|
171
|
+
- variants,
|
|
172
|
+
- );
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
5. Handle missing search query param in url from selecting a first variant
|
|
176
|
+
|
|
177
|
+
```diff
|
|
178
|
+
import {
|
|
179
|
+
getSelectedProductOptions,
|
|
180
|
+
Analytics,
|
|
181
|
+
useOptimisticVariant,
|
|
182
|
+
getAdjacentAndFirstAvailableVariants,
|
|
183
|
+
+ useSelectedOptionInUrlParam,
|
|
184
|
+
} from '@shopify/hydrogen';
|
|
185
|
+
|
|
186
|
+
export default function Product() {
|
|
187
|
+
const {product} = useLoaderData<typeof loader>();
|
|
188
|
+
|
|
189
|
+
// Optimistically selects a variant with given available variant information
|
|
190
|
+
const selectedVariant = useOptimisticVariant(
|
|
191
|
+
product.selectedOrFirstAvailableVariant,
|
|
192
|
+
getAdjacentAndFirstAvailableVariants(product),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
+ // Sets the search param to the selected variant without navigation
|
|
196
|
+
+ // only when no search params are set in the url
|
|
197
|
+
+ useSelectedOptionInUrlParam(selectedVariant.selectedOptions);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
6. Get the product options array using `getProductOptions`
|
|
201
|
+
|
|
202
|
+
```diff
|
|
203
|
+
import {
|
|
204
|
+
getSelectedProductOptions,
|
|
205
|
+
Analytics,
|
|
206
|
+
useOptimisticVariant,
|
|
207
|
+
+ getProductOptions,
|
|
208
|
+
getAdjacentAndFirstAvailableVariants,
|
|
209
|
+
useSelectedOptionInUrlParam,
|
|
210
|
+
} from '@shopify/hydrogen';
|
|
211
|
+
|
|
212
|
+
export default function Product() {
|
|
213
|
+
const {product} = useLoaderData<typeof loader>();
|
|
214
|
+
|
|
215
|
+
// Optimistically selects a variant with given available variant information
|
|
216
|
+
const selectedVariant = useOptimisticVariant(
|
|
217
|
+
product.selectedOrFirstAvailableVariant,
|
|
218
|
+
getAdjacentAndFirstAvailableVariants(product),
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
// Sets the search param to the selected variant without navigation
|
|
222
|
+
// only when no search params are set in the url
|
|
223
|
+
useSelectedOptionInUrlParam(selectedVariant.selectedOptions);
|
|
224
|
+
|
|
225
|
+
+ // Get the product options array
|
|
226
|
+
+ const productOptions = getProductOptions({
|
|
227
|
+
+ ...product,
|
|
228
|
+
+ selectedOrFirstAvailableVariant: selectedVariant,
|
|
229
|
+
+ });
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
7. Remove the `Await` and `Suspense` from the `ProductForm`. We no longer have any queries that we need to wait for.
|
|
233
|
+
|
|
234
|
+
```diff
|
|
235
|
+
export default function Product() {
|
|
236
|
+
|
|
237
|
+
...
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
...
|
|
241
|
+
+ <ProductForm
|
|
242
|
+
+ productOptions={productOptions}
|
|
243
|
+
+ selectedVariant={selectedVariant}
|
|
244
|
+
+ />
|
|
245
|
+
- <Suspense
|
|
246
|
+
- fallback={
|
|
247
|
+
- <ProductForm
|
|
248
|
+
- product={product}
|
|
249
|
+
- selectedVariant={selectedVariant}
|
|
250
|
+
- variants={[]}
|
|
251
|
+
- />
|
|
252
|
+
- }
|
|
253
|
+
- >
|
|
254
|
+
- <Await
|
|
255
|
+
- errorElement="There was a problem loading product variants"
|
|
256
|
+
- resolve={variants}
|
|
257
|
+
- >
|
|
258
|
+
- {(data) => (
|
|
259
|
+
- <ProductForm
|
|
260
|
+
- product={product}
|
|
261
|
+
- selectedVariant={selectedVariant}
|
|
262
|
+
- variants={data?.product?.variants.nodes || []}
|
|
263
|
+
- />
|
|
264
|
+
- )}
|
|
265
|
+
- </Await>
|
|
266
|
+
- </Suspense>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
8. Update the `ProductForm` component.
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
import {Link, useNavigate} from '@remix-run/react';
|
|
273
|
+
import {type MappedProductOptions} from '@shopify/hydrogen';
|
|
274
|
+
import type {
|
|
275
|
+
Maybe,
|
|
276
|
+
ProductOptionValueSwatch,
|
|
277
|
+
} from '@shopify/hydrogen/storefront-api-types';
|
|
278
|
+
import {AddToCartButton} from './AddToCartButton';
|
|
279
|
+
import {useAside} from './Aside';
|
|
280
|
+
import type {ProductFragment} from 'storefrontapi.generated';
|
|
281
|
+
|
|
282
|
+
export function ProductForm({
|
|
283
|
+
productOptions,
|
|
284
|
+
selectedVariant,
|
|
285
|
+
}: {
|
|
286
|
+
productOptions: MappedProductOptions[];
|
|
287
|
+
selectedVariant: ProductFragment['selectedOrFirstAvailableVariant'];
|
|
288
|
+
}) {
|
|
289
|
+
const navigate = useNavigate();
|
|
290
|
+
const {open} = useAside();
|
|
291
|
+
return (
|
|
292
|
+
<div className="product-form">
|
|
293
|
+
{productOptions.map((option) => (
|
|
294
|
+
<div className="product-options" key={option.name}>
|
|
295
|
+
<h5>{option.name}</h5>
|
|
296
|
+
<div className="product-options-grid">
|
|
297
|
+
{option.optionValues.map((value) => {
|
|
298
|
+
const {
|
|
299
|
+
name,
|
|
300
|
+
handle,
|
|
301
|
+
variantUriQuery,
|
|
302
|
+
selected,
|
|
303
|
+
available,
|
|
304
|
+
exists,
|
|
305
|
+
isDifferentProduct,
|
|
306
|
+
swatch,
|
|
307
|
+
} = value;
|
|
308
|
+
|
|
309
|
+
if (isDifferentProduct) {
|
|
310
|
+
// SEO
|
|
311
|
+
// When the variant is a combined listing child product
|
|
312
|
+
// that leads to a different url, we need to render it
|
|
313
|
+
// as an anchor tag
|
|
314
|
+
return (
|
|
315
|
+
<Link
|
|
316
|
+
className="product-options-item"
|
|
317
|
+
key={option.name + name}
|
|
318
|
+
prefetch="intent"
|
|
319
|
+
preventScrollReset
|
|
320
|
+
replace
|
|
321
|
+
to={`/products/${handle}?${variantUriQuery}`}
|
|
322
|
+
style={{
|
|
323
|
+
border: selected
|
|
324
|
+
? '1px solid black'
|
|
325
|
+
: '1px solid transparent',
|
|
326
|
+
opacity: available ? 1 : 0.3,
|
|
327
|
+
}}
|
|
328
|
+
>
|
|
329
|
+
<ProductOptionSwatch swatch={swatch} name={name} />
|
|
330
|
+
</Link>
|
|
331
|
+
);
|
|
332
|
+
} else {
|
|
333
|
+
// SEO
|
|
334
|
+
// When the variant is an update to the search param,
|
|
335
|
+
// render it as a button with javascript navigating to
|
|
336
|
+
// the variant so that SEO bots do not index these as
|
|
337
|
+
// duplicated links
|
|
338
|
+
return (
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
className={`product-options-item${
|
|
342
|
+
exists && !selected ? ' link' : ''
|
|
343
|
+
}`}
|
|
344
|
+
key={option.name + name}
|
|
345
|
+
style={{
|
|
346
|
+
border: selected
|
|
347
|
+
? '1px solid black'
|
|
348
|
+
: '1px solid transparent',
|
|
349
|
+
opacity: available ? 1 : 0.3,
|
|
350
|
+
}}
|
|
351
|
+
disabled={!exists}
|
|
352
|
+
onClick={() => {
|
|
353
|
+
if (!selected) {
|
|
354
|
+
navigate(`?${variantUriQuery}`, {
|
|
355
|
+
replace: true,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
<ProductOptionSwatch swatch={swatch} name={name} />
|
|
361
|
+
</button>
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
})}
|
|
365
|
+
</div>
|
|
366
|
+
<br />
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
<AddToCartButton
|
|
370
|
+
disabled={!selectedVariant || !selectedVariant.availableForSale}
|
|
371
|
+
onClick={() => {
|
|
372
|
+
open('cart');
|
|
373
|
+
}}
|
|
374
|
+
lines={
|
|
375
|
+
selectedVariant
|
|
376
|
+
? [
|
|
377
|
+
{
|
|
378
|
+
merchandiseId: selectedVariant.id,
|
|
379
|
+
quantity: 1,
|
|
380
|
+
selectedVariant,
|
|
381
|
+
},
|
|
382
|
+
]
|
|
383
|
+
: []
|
|
384
|
+
}
|
|
385
|
+
>
|
|
386
|
+
{selectedVariant?.availableForSale ? 'Add to cart' : 'Sold out'}
|
|
387
|
+
</AddToCartButton>
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function ProductOptionSwatch({
|
|
393
|
+
swatch,
|
|
394
|
+
name,
|
|
395
|
+
}: {
|
|
396
|
+
swatch?: Maybe<ProductOptionValueSwatch> | undefined;
|
|
397
|
+
name: string;
|
|
398
|
+
}) {
|
|
399
|
+
const image = swatch?.image?.previewImage?.url;
|
|
400
|
+
const color = swatch?.color;
|
|
401
|
+
|
|
402
|
+
if (!image && !color) return name;
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<div
|
|
406
|
+
aria-label={name}
|
|
407
|
+
className="product-option-label-swatch"
|
|
408
|
+
style={{
|
|
409
|
+
backgroundColor: color || 'transparent',
|
|
410
|
+
}}
|
|
411
|
+
>
|
|
412
|
+
{!!image && <img src={image} alt={name} />}
|
|
413
|
+
</div>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
9. Update `app.css`
|
|
419
|
+
|
|
420
|
+
```diff
|
|
421
|
+
+ /*
|
|
422
|
+
+ * --------------------------------------------------
|
|
423
|
+
+ * Non anchor links
|
|
424
|
+
+ * --------------------------------------------------
|
|
425
|
+
+ */
|
|
426
|
+
+ .link:hover {
|
|
427
|
+
+ text-decoration: underline;
|
|
428
|
+
+ cursor: pointer;
|
|
429
|
+
+ }
|
|
430
|
+
|
|
431
|
+
...
|
|
432
|
+
|
|
433
|
+
- .product-options-item {
|
|
434
|
+
+ .product-options-item,
|
|
435
|
+
+ .product-options-item:disabled {
|
|
436
|
+
+ padding: 0.25rem 0.5rem;
|
|
437
|
+
+ background-color: transparent;
|
|
438
|
+
+ font-size: 1rem;
|
|
439
|
+
+ font-family: inherit;
|
|
440
|
+
+ }
|
|
441
|
+
|
|
442
|
+
+ .product-option-label-swatch {
|
|
443
|
+
+ width: 1.25rem;
|
|
444
|
+
+ height: 1.25rem;
|
|
445
|
+
+ margin: 0.25rem 0;
|
|
446
|
+
+ }
|
|
447
|
+
|
|
448
|
+
+ .product-option-label-swatch img {
|
|
449
|
+
+ width: 100%;
|
|
450
|
+
+ }
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
10. Update `lib/variants.ts`
|
|
454
|
+
|
|
455
|
+
Make `useVariantUrl` and `getVariantUrl` flexible to supplying a selected option param
|
|
456
|
+
|
|
457
|
+
```diff
|
|
458
|
+
export function useVariantUrl(
|
|
459
|
+
handle: string,
|
|
460
|
+
- selectedOptions: SelectedOption[],
|
|
461
|
+
+ selectedOptions?: SelectedOption[],
|
|
462
|
+
) {
|
|
463
|
+
const {pathname} = useLocation();
|
|
464
|
+
|
|
465
|
+
return useMemo(() => {
|
|
466
|
+
return getVariantUrl({
|
|
467
|
+
handle,
|
|
468
|
+
pathname,
|
|
469
|
+
searchParams: new URLSearchParams(),
|
|
470
|
+
selectedOptions,
|
|
471
|
+
});
|
|
472
|
+
}, [handle, selectedOptions, pathname]);
|
|
473
|
+
}
|
|
474
|
+
export function getVariantUrl({
|
|
475
|
+
handle,
|
|
476
|
+
pathname,
|
|
477
|
+
searchParams,
|
|
478
|
+
selectedOptions,
|
|
479
|
+
}: {
|
|
480
|
+
handle: string;
|
|
481
|
+
pathname: string;
|
|
482
|
+
searchParams: URLSearchParams;
|
|
483
|
+
- selectedOptions: SelectedOption[];
|
|
484
|
+
+ selectedOptions?: SelectedOption[],
|
|
485
|
+
}) {
|
|
486
|
+
const match = /(\/[a-zA-Z]{2}-[a-zA-Z]{2}\/)/g.exec(pathname);
|
|
487
|
+
const isLocalePathname = match && match.length > 0;
|
|
488
|
+
const path = isLocalePathname
|
|
489
|
+
? `${match![0]}products/${handle}`
|
|
490
|
+
: `/products/${handle}`;
|
|
491
|
+
|
|
492
|
+
- selectedOptions.forEach((option) => {
|
|
493
|
+
+ selectedOptions?.forEach((option) => {
|
|
494
|
+
searchParams.set(option.name, option.value);
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
11. Update `routes/collections.$handle.tsx`
|
|
499
|
+
|
|
500
|
+
We no longer need to query for the variants since product route can efficiently
|
|
501
|
+
obtain the first available variants. Update the code to reflect that:
|
|
502
|
+
|
|
503
|
+
```diff
|
|
504
|
+
const PRODUCT_ITEM_FRAGMENT = `#graphql
|
|
505
|
+
fragment MoneyProductItem on MoneyV2 {
|
|
506
|
+
amount
|
|
507
|
+
currencyCode
|
|
508
|
+
}
|
|
509
|
+
fragment ProductItem on Product {
|
|
510
|
+
id
|
|
511
|
+
handle
|
|
512
|
+
title
|
|
513
|
+
featuredImage {
|
|
514
|
+
id
|
|
515
|
+
altText
|
|
516
|
+
url
|
|
517
|
+
width
|
|
518
|
+
height
|
|
519
|
+
}
|
|
520
|
+
priceRange {
|
|
521
|
+
minVariantPrice {
|
|
522
|
+
...MoneyProductItem
|
|
523
|
+
}
|
|
524
|
+
maxVariantPrice {
|
|
525
|
+
...MoneyProductItem
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
- variants(first: 1) {
|
|
529
|
+
- nodes {
|
|
530
|
+
- selectedOptions {
|
|
531
|
+
- name
|
|
532
|
+
- value
|
|
533
|
+
- }
|
|
534
|
+
- }
|
|
535
|
+
- }
|
|
536
|
+
}
|
|
537
|
+
` as const;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
and remove the variant reference
|
|
541
|
+
|
|
542
|
+
```diff
|
|
543
|
+
function ProductItem({
|
|
544
|
+
product,
|
|
545
|
+
loading,
|
|
546
|
+
}: {
|
|
547
|
+
product: ProductItemFragment;
|
|
548
|
+
loading?: 'eager' | 'lazy';
|
|
549
|
+
}) {
|
|
550
|
+
- const variant = product.variants.nodes[0];
|
|
551
|
+
- const variantUrl = useVariantUrl(product.handle, variant.selectedOptions);
|
|
552
|
+
+ const variantUrl = useVariantUrl(product.handle);
|
|
553
|
+
return (
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
12. Update `routes/collections.all.tsx`
|
|
557
|
+
|
|
558
|
+
Same reasoning as `collections.$handle.tsx`
|
|
559
|
+
|
|
560
|
+
```diff
|
|
561
|
+
const PRODUCT_ITEM_FRAGMENT = `#graphql
|
|
562
|
+
fragment MoneyProductItem on MoneyV2 {
|
|
563
|
+
amount
|
|
564
|
+
currencyCode
|
|
565
|
+
}
|
|
566
|
+
fragment ProductItem on Product {
|
|
567
|
+
id
|
|
568
|
+
handle
|
|
569
|
+
title
|
|
570
|
+
featuredImage {
|
|
571
|
+
id
|
|
572
|
+
altText
|
|
573
|
+
url
|
|
574
|
+
width
|
|
575
|
+
height
|
|
576
|
+
}
|
|
577
|
+
priceRange {
|
|
578
|
+
minVariantPrice {
|
|
579
|
+
...MoneyProductItem
|
|
580
|
+
}
|
|
581
|
+
maxVariantPrice {
|
|
582
|
+
...MoneyProductItem
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
- variants(first: 1) {
|
|
586
|
+
- nodes {
|
|
587
|
+
- selectedOptions {
|
|
588
|
+
- name
|
|
589
|
+
- value
|
|
590
|
+
- }
|
|
591
|
+
- }
|
|
592
|
+
- }
|
|
593
|
+
}
|
|
594
|
+
` as const;
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
and remove the variant reference
|
|
598
|
+
|
|
599
|
+
```diff
|
|
600
|
+
function ProductItem({
|
|
601
|
+
product,
|
|
602
|
+
loading,
|
|
603
|
+
}: {
|
|
604
|
+
product: ProductItemFragment;
|
|
605
|
+
loading?: 'eager' | 'lazy';
|
|
606
|
+
}) {
|
|
607
|
+
- const variant = product.variants.nodes[0];
|
|
608
|
+
- const variantUrl = useVariantUrl(product.handle, variant.selectedOptions);
|
|
609
|
+
+ const variantUrl = useVariantUrl(product.handle);
|
|
610
|
+
return (
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
13. Update `routes/search.tsx`
|
|
614
|
+
|
|
615
|
+
Instead of using the first variant, use `selectedOrFirstAvailableVariant`
|
|
616
|
+
|
|
617
|
+
```diff
|
|
618
|
+
const SEARCH_PRODUCT_FRAGMENT = `#graphql
|
|
619
|
+
fragment SearchProduct on Product {
|
|
620
|
+
__typename
|
|
621
|
+
handle
|
|
622
|
+
id
|
|
623
|
+
publishedAt
|
|
624
|
+
title
|
|
625
|
+
trackingParameters
|
|
626
|
+
vendor
|
|
627
|
+
- variants(first: 1) {
|
|
628
|
+
- nodes {
|
|
629
|
+
+ selectedOrFirstAvailableVariant(
|
|
630
|
+
+ selectedOptions: []
|
|
631
|
+
+ ignoreUnknownOptions: true
|
|
632
|
+
+ caseInsensitiveMatch: true
|
|
633
|
+
+ ) {
|
|
634
|
+
id
|
|
635
|
+
image {
|
|
636
|
+
url
|
|
637
|
+
altText
|
|
638
|
+
width
|
|
639
|
+
height
|
|
640
|
+
}
|
|
641
|
+
price {
|
|
642
|
+
amount
|
|
643
|
+
currencyCode
|
|
644
|
+
}
|
|
645
|
+
compareAtPrice {
|
|
646
|
+
amount
|
|
647
|
+
currencyCode
|
|
648
|
+
}
|
|
649
|
+
selectedOptions {
|
|
650
|
+
name
|
|
651
|
+
value
|
|
652
|
+
}
|
|
653
|
+
product {
|
|
654
|
+
handle
|
|
655
|
+
title
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
- }
|
|
659
|
+
}
|
|
660
|
+
` as const;
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
```diff
|
|
664
|
+
const PREDICTIVE_SEARCH_PRODUCT_FRAGMENT = `#graphql
|
|
665
|
+
fragment PredictiveProduct on Product {
|
|
666
|
+
__typename
|
|
667
|
+
id
|
|
668
|
+
title
|
|
669
|
+
handle
|
|
670
|
+
trackingParameters
|
|
671
|
+
- variants(first: 1) {
|
|
672
|
+
- nodes {
|
|
673
|
+
+ selectedOrFirstAvailableVariant(
|
|
674
|
+
+ selectedOptions: []
|
|
675
|
+
+ ignoreUnknownOptions: true
|
|
676
|
+
+ caseInsensitiveMatch: true
|
|
677
|
+
+ ) {
|
|
678
|
+
id
|
|
679
|
+
image {
|
|
680
|
+
url
|
|
681
|
+
altText
|
|
682
|
+
width
|
|
683
|
+
height
|
|
684
|
+
}
|
|
685
|
+
price {
|
|
686
|
+
amount
|
|
687
|
+
currencyCode
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
- }
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
14. Update `components/SearchResults.tsx`
|
|
695
|
+
|
|
696
|
+
```diff
|
|
697
|
+
function SearchResultsProducts({
|
|
698
|
+
term,
|
|
699
|
+
products,
|
|
700
|
+
}: PartialSearchResult<'products'>) {
|
|
701
|
+
if (!products?.nodes.length) {
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return (
|
|
706
|
+
<div className="search-result">
|
|
707
|
+
<h2>Products</h2>
|
|
708
|
+
<Pagination connection={products}>
|
|
709
|
+
{({nodes, isLoading, NextLink, PreviousLink}) => {
|
|
710
|
+
const ItemsMarkup = nodes.map((product) => {
|
|
711
|
+
const productUrl = urlWithTrackingParams({
|
|
712
|
+
baseUrl: `/products/${product.handle}`,
|
|
713
|
+
trackingParams: product.trackingParameters,
|
|
714
|
+
term,
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
+ const price = product?.selectedOrFirstAvailableVariant?.price;
|
|
718
|
+
+ const image = product?.selectedOrFirstAvailableVariant?.image;
|
|
719
|
+
|
|
720
|
+
return (
|
|
721
|
+
<div className="search-results-item" key={product.id}>
|
|
722
|
+
<Link prefetch="intent" to={productUrl}>
|
|
723
|
+
- {product.variants.nodes[0].image && (
|
|
724
|
+
+ {image && (
|
|
725
|
+
<Image
|
|
726
|
+
- data={product.variants.nodes[0].image}
|
|
727
|
+
+ data={image}
|
|
728
|
+
alt={product.title}
|
|
729
|
+
width={50}
|
|
730
|
+
/>
|
|
731
|
+
)}
|
|
732
|
+
<div>
|
|
733
|
+
<p>{product.title}</p>
|
|
734
|
+
<small>
|
|
735
|
+
- <Money data={product.variants.nodes[0].price} />
|
|
736
|
+
+ {price &&
|
|
737
|
+
+ <Money data={price} />
|
|
738
|
+
+ }
|
|
739
|
+
</small>
|
|
740
|
+
</div>
|
|
741
|
+
</Link>
|
|
742
|
+
</div>
|
|
743
|
+
);
|
|
744
|
+
});
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
15. Update `components/SearchResultsPredictive.tsx`
|
|
748
|
+
|
|
749
|
+
```diff
|
|
750
|
+
function SearchResultsPredictiveProducts({
|
|
751
|
+
term,
|
|
752
|
+
products,
|
|
753
|
+
closeSearch,
|
|
754
|
+
}: PartialPredictiveSearchResult<'products'>) {
|
|
755
|
+
if (!products.length) return null;
|
|
756
|
+
|
|
757
|
+
return (
|
|
758
|
+
<div className="predictive-search-result" key="products">
|
|
759
|
+
<h5>Products</h5>
|
|
760
|
+
<ul>
|
|
761
|
+
{products.map((product) => {
|
|
762
|
+
const productUrl = urlWithTrackingParams({
|
|
763
|
+
baseUrl: `/products/${product.handle}`,
|
|
764
|
+
trackingParams: product.trackingParameters,
|
|
765
|
+
term: term.current,
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
+ const price = product?.selectedOrFirstAvailableVariant?.price;
|
|
769
|
+
- const image = product?.variants?.nodes?.[0].image;
|
|
770
|
+
+ const image = product?.selectedOrFirstAvailableVariant?.image;
|
|
771
|
+
return (
|
|
772
|
+
<li className="predictive-search-result-item" key={product.id}>
|
|
773
|
+
<Link to={productUrl} onClick={closeSearch}>
|
|
774
|
+
{image && (
|
|
775
|
+
<Image
|
|
776
|
+
alt={image.altText ?? ''}
|
|
777
|
+
src={image.url}
|
|
778
|
+
width={50}
|
|
779
|
+
height={50}
|
|
780
|
+
/>
|
|
781
|
+
)}
|
|
782
|
+
<div>
|
|
783
|
+
<p>{product.title}</p>
|
|
784
|
+
<small>
|
|
785
|
+
- {product?.variants?.nodes?.[0].price && (
|
|
786
|
+
+ {price && (
|
|
787
|
+
- <Money data={product.variants.nodes[0].price} />
|
|
788
|
+
+ <Money data={price} />
|
|
789
|
+
)}
|
|
790
|
+
</small>
|
|
791
|
+
</div>
|
|
792
|
+
</Link>
|
|
793
|
+
</li>
|
|
794
|
+
);
|
|
795
|
+
})}
|
|
796
|
+
</ul>
|
|
797
|
+
</div>
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
- Update `Aside` to have an accessible close button label ([#2639](https://github.com/Shopify/hydrogen/pull/2639)) by [@lb-](https://github.com/lb-)
|
|
803
|
+
|
|
804
|
+
- Fix cart route so that it works with no-js ([#2665](https://github.com/Shopify/hydrogen/pull/2665)) by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
805
|
+
|
|
806
|
+
- Bump Shopify cli version ([#2667](https://github.com/Shopify/hydrogen/pull/2667)) by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
807
|
+
|
|
808
|
+
- Updated dependencies [[`8f64915e`](https://github.com/Shopify/hydrogen/commit/8f64915e934130299307417627a12caf756cd8da), [`a57d5267`](https://github.com/Shopify/hydrogen/commit/a57d5267daa2f22fe1a426fb9f62c242957f95b6), [`91d60fd2`](https://github.com/Shopify/hydrogen/commit/91d60fd2174b7c34f9f6b781cd5f0a70371fd899), [`23a80f3e`](https://github.com/Shopify/hydrogen/commit/23a80f3e7bf9f9908130fc9345397fc694420364)]:
|
|
809
|
+
- @shopify/hydrogen@2024.10.1
|
|
810
|
+
|
|
811
|
+
## 2024.10.1
|
|
812
|
+
|
|
813
|
+
### Patch Changes
|
|
814
|
+
|
|
815
|
+
- Bump to get new cli package version by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
816
|
+
|
|
3
817
|
## 2024.10.0
|
|
4
818
|
|
|
5
819
|
### Patch Changes
|