@shopify/create-hydrogen 5.0.24 → 5.0.26
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/bundle/analyzer.html +155 -148
- package/dist/assets/hydrogen/starter/CHANGELOG.md +131 -49
- package/dist/assets/hydrogen/starter/app/components/AddToCartButton.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +62 -29
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/PageLayout.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/ProductForm.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/components/SearchForm.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/SearchFormPredictive.tsx +8 -3
- package/dist/assets/hydrogen/starter/app/components/SearchResults.tsx +3 -11
- package/dist/assets/hydrogen/starter/app/components/SearchResultsPredictive.tsx +2 -6
- package/dist/assets/hydrogen/starter/app/entry.client.tsx +10 -2
- package/dist/assets/hydrogen/starter/app/entry.server.tsx +5 -3
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerAddressMutations.ts +7 -4
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -1
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerOrderQuery.ts +4 -1
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +10 -5
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +3 -2
- package/dist/assets/hydrogen/starter/app/lib/context.ts +34 -17
- package/dist/assets/hydrogen/starter/app/lib/fragments.ts +1 -0
- package/dist/assets/hydrogen/starter/app/lib/orderFilters.ts +90 -0
- package/dist/assets/hydrogen/starter/app/lib/redirect.ts +1 -1
- package/dist/assets/hydrogen/starter/app/lib/session.ts +1 -1
- package/dist/assets/hydrogen/starter/app/lib/variants.ts +1 -1
- package/dist/assets/hydrogen/starter/app/root.tsx +23 -18
- package/dist/assets/hydrogen/starter/app/routes/$.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/[sitemap.xml].tsx +2 -3
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +12 -8
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +4 -3
- package/dist/assets/hydrogen/starter/app/routes/account._index.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +15 -11
- package/dist/assets/hydrogen/starter/app/routes/account.orders.$id.tsx +47 -22
- package/dist/assets/hydrogen/starter/app/routes/account.orders._index.tsx +152 -23
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +11 -8
- package/dist/assets/hydrogen/starter/app/routes/account.tsx +16 -4
- package/dist/assets/hydrogen/starter/app/routes/account_.authorize.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/account_.login.tsx +5 -3
- package/dist/assets/hydrogen/starter/app/routes/account_.logout.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/api.$version.[graphql.json].tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +6 -10
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +10 -7
- package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +13 -7
- package/dist/assets/hydrogen/starter/app/routes/cart.$lines.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +13 -9
- package/dist/assets/hydrogen/starter/app/routes/collections.$handle.tsx +8 -11
- package/dist/assets/hydrogen/starter/app/routes/collections._index.tsx +6 -6
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +10 -7
- package/dist/assets/hydrogen/starter/app/routes/discount.$code.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +8 -6
- package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +7 -4
- package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +19 -13
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +9 -6
- package/dist/assets/hydrogen/starter/app/routes/search.tsx +14 -14
- package/dist/assets/hydrogen/starter/app/routes/sitemap.$type.$page[.xml].tsx +2 -3
- package/dist/assets/hydrogen/starter/app/routes.ts +1 -1
- package/dist/assets/hydrogen/starter/app/styles/app.css +53 -1
- package/dist/assets/hydrogen/starter/customer-accountapi.generated.d.ts +47 -13
- package/dist/assets/hydrogen/starter/env.d.ts +1 -39
- package/dist/assets/hydrogen/starter/eslint.config.js +35 -52
- package/dist/assets/hydrogen/starter/package.json +14 -15
- package/dist/assets/hydrogen/starter/react-router.config.ts +9 -3
- package/dist/assets/hydrogen/starter/server.ts +7 -7
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +1 -1
- package/dist/assets/hydrogen/starter/tsconfig.json +17 -13
- package/dist/assets/hydrogen/starter/vite.config.ts +4 -1
- package/dist/assets/hydrogen/virtual-routes/components/RequestDetails.jsx +13 -20
- package/dist/assets/hydrogen/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.jsx +37 -0
- package/dist/chunk-2LZQLWDR.js +1189 -0
- package/dist/{chunk-EO6F7WJJ.js → chunk-6YUUFKYO.js} +1 -1
- package/dist/chunk-AUULK6IN.js +5 -0
- package/dist/chunk-CJKPLQJ7.js +51 -0
- package/dist/{chunk-MNT4XW23.js → chunk-LBUW5UHX.js} +1 -1
- package/dist/chunk-RUCJI22O.js +3 -0
- package/dist/{chunk-PMDMUCNY.js → chunk-VXJIQGAB.js} +1 -1
- package/dist/chunk-Y5VZE2FH.js +32 -0
- package/dist/chunk-ZLNTSIDN.js +2 -0
- package/dist/create-app.js +293 -288
- package/dist/{del-72VO4HYK.js → del-VDYQZFAQ.js} +1 -1
- package/dist/devtools-3BYEW2L2.js +8 -0
- package/dist/error-handler-XRI3ZDLO.js +2 -0
- package/dist/is-wsl-52AELLDM.js +2 -0
- package/dist/{morph-3JSBLNUD.js → morph-S2LU6PQ4.js} +7 -7
- package/dist/{multipart-parser-QIHQVIZA.js → multipart-parser-MX4R5XJM.js} +1 -1
- package/dist/open-PMJ32HTM.js +2 -0
- package/dist/out-U7AI7XUQ.js +2 -0
- package/package.json +4 -2
- package/dist/chokidar-FXMI63T6.js +0 -12
- package/dist/chunk-3LZ6M5C2.js +0 -3
- package/dist/chunk-D7CI46F7.js +0 -10
- package/dist/chunk-FB327AH7.js +0 -5
- package/dist/chunk-MZPD7BFF.js +0 -23
- package/dist/chunk-QUKX7CP5.js +0 -1180
- package/dist/chunk-UASQ33JG.js +0 -45
- package/dist/chunk-VMIOG46Y.js +0 -2
- package/dist/devtools-DGRGSZU7.js +0 -8
- package/dist/error-handler-YXM2BB34.js +0 -2
- package/dist/is-wsl-LL6KGQIK.js +0 -2
- package/dist/open-OD6DRFEG.js +0 -2
- package/dist/out-DXB3K325.js +0 -2
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# skeleton
|
|
2
2
|
|
|
3
|
+
## 2025.7.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Update Storefront API and Customer Account API to version 2025-07 ([#3082](https://github.com/Shopify/hydrogen/pull/3082)) by [@juanpprieto](https://github.com/juanpprieto)
|
|
8
|
+
|
|
9
|
+
This update includes:
|
|
10
|
+
- Updated API version constants to 2025-07
|
|
11
|
+
- Regenerated GraphQL types for both Storefront and Customer Account APIs
|
|
12
|
+
- Updated all hardcoded API version references in documentation and tests
|
|
13
|
+
- Regenerated skeleton template types
|
|
14
|
+
- Updated skeleton's @shopify/cli dependency to ~3.83.3
|
|
15
|
+
|
|
16
|
+
Breaking changes may occur due to API schema changes between versions.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Fix defer/streaming in development & preview ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
21
|
+
|
|
22
|
+
- Upgrade Miniflare from v2 to v4 in mini-oxygen package. ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
23
|
+
- Internal MiniOxygen API has been refactored to work with Miniflare v4's new architecture.
|
|
24
|
+
- Simplified MiniOxygen class - no longer extends MiniflareCore.
|
|
25
|
+
- Updated global fetch handling to use Miniflare v4's `outboundService` API.
|
|
26
|
+
- Fixed test infrastructure to use project-relative temporary directories.
|
|
27
|
+
- Added support for Oxygen compatibility parameters (`compatibilityDate`, `compatibilityFlags`).
|
|
28
|
+
- Removed dependency on multiple `@miniflare/*` packages in favor of the consolidated `miniflare` package.
|
|
29
|
+
|
|
30
|
+
- Update and pin react-router to 7.9.2 for 2025.7.0 ([#3138](https://github.com/Shopify/hydrogen/pull/3138)) by [@juanpprieto](https://github.com/juanpprieto)
|
|
31
|
+
|
|
32
|
+
- Add TypeScript ESLint rules for promise handling to prevent Cloudflare Workers errors ([#3146](https://github.com/Shopify/hydrogen/pull/3146)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
33
|
+
|
|
34
|
+
Added `@typescript-eslint/no-floating-promises` and `@typescript-eslint/no-misused-promises` rules to help prevent "The script will never generate a response" errors when deploying to Oxygen/Cloudflare Workers. These rules ensure promises are properly handled with await, return, or void operators, as recommended by [Cloudflare's error documentation](https://developers.cloudflare.com/workers/observability/errors/#the-script-will-never-generate-a-response-errors).
|
|
35
|
+
|
|
36
|
+
- Fixed React Context error that occurred during client-side hydration when using Content Security Policy (CSP) with nonces. The error "Cannot read properties of null (reading 'useContext')" was caused by the `NonceProvider` being present during server-side rendering but missing during client hydration. ([#3082](https://github.com/Shopify/hydrogen/pull/3082)) by [@juanpprieto](https://github.com/juanpprieto)
|
|
37
|
+
|
|
38
|
+
#### Changes for Existing Projects
|
|
39
|
+
|
|
40
|
+
If you have customized your `app/entry.client.tsx` file, you may need to wrap your app with the `NonceProvider` during hydration to avoid this error:
|
|
41
|
+
|
|
42
|
+
```diff
|
|
43
|
+
// app/entry.client.tsx
|
|
44
|
+
import {HydratedRouter} from 'react-router/dom';
|
|
45
|
+
import {startTransition, StrictMode} from 'react';
|
|
46
|
+
import {hydrateRoot} from 'react-dom/client';
|
|
47
|
+
+ import {NonceProvider} from '@shopify/hydrogen';
|
|
48
|
+
|
|
49
|
+
if (!window.location.origin.includes('webcache.googleusercontent.com')) {
|
|
50
|
+
startTransition(() => {
|
|
51
|
+
+ // Extract nonce from existing script tags
|
|
52
|
+
+ const existingNonce = document
|
|
53
|
+
+ .querySelector<HTMLScriptElement>('script[nonce]')
|
|
54
|
+
+ ?.nonce;
|
|
55
|
+
+
|
|
56
|
+
hydrateRoot(
|
|
57
|
+
document,
|
|
58
|
+
<StrictMode>
|
|
59
|
+
- <HydratedRouter />
|
|
60
|
+
+ <NonceProvider value={existingNonce}>
|
|
61
|
+
+ <HydratedRouter />
|
|
62
|
+
+ </NonceProvider>
|
|
63
|
+
</StrictMode>,
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This ensures the React Context tree matches between server and client rendering, preventing hydration mismatches.
|
|
70
|
+
|
|
71
|
+
#### Package Changes
|
|
72
|
+
- **@shopify/hydrogen**: Exported `NonceProvider` from the main package to allow client-side usage and simplified Vite configuration to improve React Context stability during development
|
|
73
|
+
- **skeleton**: Updated the template's `entry.client.tsx` to include the `NonceProvider` wrapper during hydration
|
|
74
|
+
|
|
75
|
+
- Add `fulfillmentStatus` to CAAPI order query and route ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
76
|
+
|
|
77
|
+
- Add GraphQL @defer directive support to storefront client ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
78
|
+
|
|
79
|
+
- Unpin react-router and react-router-dom versions in the skeleton template ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
80
|
+
|
|
81
|
+
- Add `@inContext` language support to Customer Account API mutations ([#3039](https://github.com/Shopify/hydrogen/pull/3039)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
82
|
+
|
|
83
|
+
- Add order filtering support to the skeleton /account/orders route for Customer Account API flow ([#3125](https://github.com/Shopify/hydrogen/pull/3125)) by [@juanpprieto](https://github.com/juanpprieto)
|
|
84
|
+
|
|
85
|
+
- Updated dependencies [[`6d067665562223ce2865f1c14be54b0b50258bd4`](https://github.com/Shopify/hydrogen/commit/6d067665562223ce2865f1c14be54b0b50258bd4), [`d57782a1ae3fa0017836d6010fb6ac5ab5d25965`](https://github.com/Shopify/hydrogen/commit/d57782a1ae3fa0017836d6010fb6ac5ab5d25965), [`48cbd450699a29a5667bee7174f3856430508ecc`](https://github.com/Shopify/hydrogen/commit/48cbd450699a29a5667bee7174f3856430508ecc), [`6d067665562223ce2865f1c14be54b0b50258bd4`](https://github.com/Shopify/hydrogen/commit/6d067665562223ce2865f1c14be54b0b50258bd4), [`0b4f01c9aa0e09332140a6a4e3114949873fb0f9`](https://github.com/Shopify/hydrogen/commit/0b4f01c9aa0e09332140a6a4e3114949873fb0f9), [`0d165ff280692411712176427bcd7e0df43b56fe`](https://github.com/Shopify/hydrogen/commit/0d165ff280692411712176427bcd7e0df43b56fe), [`ae7bedc89c1968b4a035f421b5ee6908f6376b1b`](https://github.com/Shopify/hydrogen/commit/ae7bedc89c1968b4a035f421b5ee6908f6376b1b), [`ae7bedc89c1968b4a035f421b5ee6908f6376b1b`](https://github.com/Shopify/hydrogen/commit/ae7bedc89c1968b4a035f421b5ee6908f6376b1b), [`75623a5bfdd8d6f0eab0d3547860341c20d9076c`](https://github.com/Shopify/hydrogen/commit/75623a5bfdd8d6f0eab0d3547860341c20d9076c), [`6681f92e84d42b5a6aca153fb49e31dcd8af84f6`](https://github.com/Shopify/hydrogen/commit/6681f92e84d42b5a6aca153fb49e31dcd8af84f6), [`4daf37ea291334b23bd543fdad5673ab7c9a6133`](https://github.com/Shopify/hydrogen/commit/4daf37ea291334b23bd543fdad5673ab7c9a6133)]:
|
|
86
|
+
- @shopify/hydrogen@2026.0.0
|
|
87
|
+
|
|
88
|
+
## 2025.5.2
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- Fixing the skeleton's Vite Config ([#2958](https://github.com/Shopify/hydrogen/pull/2958)) by [@balazsbajorics](https://github.com/balazsbajorics)
|
|
93
|
+
|
|
3
94
|
## 2025.5.1
|
|
4
95
|
|
|
5
96
|
### Patch Changes
|
|
@@ -34,7 +125,6 @@
|
|
|
34
125
|
### Patch Changes
|
|
35
126
|
|
|
36
127
|
- Fix an issue with our starter template where duplicate content can exist on URLs that use internationalized handles. For example, if you have a product handle in english of `the-havoc` and translate it to `das-chaos` in German, duplicate content exists at both: ([#2821](https://github.com/Shopify/hydrogen/pull/2821)) by [@blittle](https://github.com/blittle)
|
|
37
|
-
|
|
38
128
|
1. https://hydrogen.shop/de-de/products/das-chaos
|
|
39
129
|
2. https://hydrogen.shop/de-de/products/the-havoc
|
|
40
130
|
|
|
@@ -54,7 +144,6 @@
|
|
|
54
144
|
### Patch Changes
|
|
55
145
|
|
|
56
146
|
- Moved the `Layout` component back into `root.tsx` to avoid issues with styled errors. ([#2829](https://github.com/Shopify/hydrogen/pull/2829)) by [@ruggishop](https://github.com/ruggishop)
|
|
57
|
-
|
|
58
147
|
1. If you have a separate `app/layout.tsx` file, delete it and move its default exported component into your `root.tsx`. For example:
|
|
59
148
|
|
|
60
149
|
```ts
|
|
@@ -108,7 +197,6 @@
|
|
|
108
197
|
- Support for the Remix future flag `v3_routeConfig`. ([#2722](https://github.com/Shopify/hydrogen/pull/2722)) by [@seanparsons](https://github.com/seanparsons)
|
|
109
198
|
|
|
110
199
|
Please refer to the Remix documentation for more details on `v3_routeConfig` future flag: [https://remix.run/docs/en/main/start/future-flags#v3_routeconfig](https://remix.run/docs/en/main/start/future-flags#v3_routeconfig)
|
|
111
|
-
|
|
112
200
|
1. Update your `vite.config.ts`.
|
|
113
201
|
|
|
114
202
|
```diff
|
|
@@ -166,13 +254,13 @@
|
|
|
166
254
|
1. Add a routes.ts file. This is your new Remix route configuration file.
|
|
167
255
|
|
|
168
256
|
```ts
|
|
169
|
-
import {
|
|
170
|
-
import {
|
|
171
|
-
import {
|
|
257
|
+
import {flatRoutes} from '@remix-run/fs-routes';
|
|
258
|
+
import {layout, type RouteConfig} from '@remix-run/route-config';
|
|
259
|
+
import {hydrogenRoutes} from '@shopify/hydrogen';
|
|
172
260
|
|
|
173
261
|
export default hydrogenRoutes([
|
|
174
262
|
// Your entire app reading from routes folder using Layout from layout.tsx
|
|
175
|
-
layout(
|
|
263
|
+
layout('./layout.tsx', await flatRoutes()),
|
|
176
264
|
]) satisfies RouteConfig;
|
|
177
265
|
```
|
|
178
266
|
|
|
@@ -203,7 +291,6 @@
|
|
|
203
291
|
Remix single fetch migration guide: https://remix.run/docs/en/main/guides/single-fetch
|
|
204
292
|
|
|
205
293
|
**Note:** If you have any routes that appends (or looks for) a search param named `_data`, make sure to rename it to something else.
|
|
206
|
-
|
|
207
294
|
1. In your `vite.config.ts`, add the single fetch future flag.
|
|
208
295
|
|
|
209
296
|
```diff
|
|
@@ -501,7 +588,6 @@
|
|
|
501
588
|
- Remove initial redirect from product display page ([#2643](https://github.com/Shopify/hydrogen/pull/2643)) by [@scottdixon](https://github.com/scottdixon)
|
|
502
589
|
|
|
503
590
|
- 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)
|
|
504
|
-
|
|
505
591
|
1. Update your SFAPI product query to bring in the new query fields:
|
|
506
592
|
|
|
507
593
|
```diff
|
|
@@ -763,25 +849,25 @@
|
|
|
763
849
|
8. Update the `ProductForm` component.
|
|
764
850
|
|
|
765
851
|
```tsx
|
|
766
|
-
import {
|
|
767
|
-
import {
|
|
852
|
+
import {Link, useNavigate} from '@remix-run/react';
|
|
853
|
+
import {type MappedProductOptions} from '@shopify/hydrogen';
|
|
768
854
|
import type {
|
|
769
855
|
Maybe,
|
|
770
856
|
ProductOptionValueSwatch,
|
|
771
|
-
} from
|
|
772
|
-
import {
|
|
773
|
-
import {
|
|
774
|
-
import type {
|
|
857
|
+
} from '@shopify/hydrogen/storefront-api-types';
|
|
858
|
+
import {AddToCartButton} from './AddToCartButton';
|
|
859
|
+
import {useAside} from './Aside';
|
|
860
|
+
import type {ProductFragment} from 'storefrontapi.generated';
|
|
775
861
|
|
|
776
862
|
export function ProductForm({
|
|
777
863
|
productOptions,
|
|
778
864
|
selectedVariant,
|
|
779
865
|
}: {
|
|
780
866
|
productOptions: MappedProductOptions[];
|
|
781
|
-
selectedVariant: ProductFragment[
|
|
867
|
+
selectedVariant: ProductFragment['selectedOrFirstAvailableVariant'];
|
|
782
868
|
}) {
|
|
783
869
|
const navigate = useNavigate();
|
|
784
|
-
const {
|
|
870
|
+
const {open} = useAside();
|
|
785
871
|
return (
|
|
786
872
|
<div className="product-form">
|
|
787
873
|
{productOptions.map((option) => (
|
|
@@ -815,8 +901,8 @@
|
|
|
815
901
|
to={`/products/${handle}?${variantUriQuery}`}
|
|
816
902
|
style={{
|
|
817
903
|
border: selected
|
|
818
|
-
?
|
|
819
|
-
:
|
|
904
|
+
? '1px solid black'
|
|
905
|
+
: '1px solid transparent',
|
|
820
906
|
opacity: available ? 1 : 0.3,
|
|
821
907
|
}}
|
|
822
908
|
>
|
|
@@ -833,13 +919,13 @@
|
|
|
833
919
|
<button
|
|
834
920
|
type="button"
|
|
835
921
|
className={`product-options-item${
|
|
836
|
-
exists && !selected ?
|
|
922
|
+
exists && !selected ? ' link' : ''
|
|
837
923
|
}`}
|
|
838
924
|
key={option.name + name}
|
|
839
925
|
style={{
|
|
840
926
|
border: selected
|
|
841
|
-
?
|
|
842
|
-
:
|
|
927
|
+
? '1px solid black'
|
|
928
|
+
: '1px solid transparent',
|
|
843
929
|
opacity: available ? 1 : 0.3,
|
|
844
930
|
}}
|
|
845
931
|
disabled={!exists}
|
|
@@ -863,7 +949,7 @@
|
|
|
863
949
|
<AddToCartButton
|
|
864
950
|
disabled={!selectedVariant || !selectedVariant.availableForSale}
|
|
865
951
|
onClick={() => {
|
|
866
|
-
open(
|
|
952
|
+
open('cart');
|
|
867
953
|
}}
|
|
868
954
|
lines={
|
|
869
955
|
selectedVariant
|
|
@@ -877,7 +963,7 @@
|
|
|
877
963
|
: []
|
|
878
964
|
}
|
|
879
965
|
>
|
|
880
|
-
{selectedVariant?.availableForSale ?
|
|
966
|
+
{selectedVariant?.availableForSale ? 'Add to cart' : 'Sold out'}
|
|
881
967
|
</AddToCartButton>
|
|
882
968
|
</div>
|
|
883
969
|
);
|
|
@@ -900,7 +986,7 @@
|
|
|
900
986
|
aria-label={name}
|
|
901
987
|
className="product-option-label-swatch"
|
|
902
988
|
style={{
|
|
903
|
-
backgroundColor: color ||
|
|
989
|
+
backgroundColor: color || 'transparent',
|
|
904
990
|
}}
|
|
905
991
|
>
|
|
906
992
|
{!!image && <img src={image} alt={name} />}
|
|
@@ -1313,7 +1399,6 @@
|
|
|
1313
1399
|
### Patch Changes
|
|
1314
1400
|
|
|
1315
1401
|
- Stabilize `getSitemap`, `getSitemapIndex` and implement on skeleton ([#2589](https://github.com/Shopify/hydrogen/pull/2589)) by [@juanpprieto](https://github.com/juanpprieto)
|
|
1316
|
-
|
|
1317
1402
|
1. Update the `getSitemapIndex` at `/app/routes/[sitemap.xml].tsx`
|
|
1318
1403
|
|
|
1319
1404
|
```diff
|
|
@@ -1401,21 +1486,21 @@
|
|
|
1401
1486
|
New `withCache.fetch` is for caching simple fetch requests. This method caches the responses if they are OK responses, and you can pass `shouldCacheResponse`, `cacheKey`, etc. to modify behavior. `data` is the consumed body of the response (we need to consume to cache it).
|
|
1402
1487
|
|
|
1403
1488
|
```ts
|
|
1404
|
-
const withCache = createWithCache({
|
|
1489
|
+
const withCache = createWithCache({cache, waitUntil, request});
|
|
1405
1490
|
|
|
1406
|
-
const {
|
|
1407
|
-
|
|
1491
|
+
const {data, response} = await withCache.fetch<{data: T; error: string}>(
|
|
1492
|
+
'my-cms.com/api',
|
|
1408
1493
|
{
|
|
1409
|
-
method:
|
|
1410
|
-
headers: {
|
|
1494
|
+
method: 'POST',
|
|
1495
|
+
headers: {'Content-type': 'application/json'},
|
|
1411
1496
|
body,
|
|
1412
1497
|
},
|
|
1413
1498
|
{
|
|
1414
1499
|
cacheStrategy: CacheLong(),
|
|
1415
1500
|
// Cache if there are no data errors or a specific data that make this result not suited for caching
|
|
1416
1501
|
shouldCacheResponse: (result) => !result?.error,
|
|
1417
|
-
cacheKey: [
|
|
1418
|
-
displayName:
|
|
1502
|
+
cacheKey: ['my-cms', body],
|
|
1503
|
+
displayName: 'My CMS query',
|
|
1419
1504
|
},
|
|
1420
1505
|
);
|
|
1421
1506
|
```
|
|
@@ -1423,7 +1508,6 @@
|
|
|
1423
1508
|
- [**Breaking change**] ([#2585](https://github.com/Shopify/hydrogen/pull/2585)) by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
1424
1509
|
|
|
1425
1510
|
Deprecate usages of `product.options.values` and use `product.options.optionValues` instead.
|
|
1426
|
-
|
|
1427
1511
|
1. Update your product graphql query to use the new `optionValues` field.
|
|
1428
1512
|
|
|
1429
1513
|
```diff
|
|
@@ -1991,9 +2075,9 @@
|
|
|
1991
2075
|
|
|
1992
2076
|
```tsx
|
|
1993
2077
|
// app/lib/root-data.ts
|
|
1994
|
-
import {
|
|
1995
|
-
import type {
|
|
1996
|
-
import type {
|
|
2078
|
+
import {useMatches} from '@remix-run/react';
|
|
2079
|
+
import type {SerializeFrom} from '@shopify/remix-oxygen';
|
|
2080
|
+
import type {loader} from '~/root';
|
|
1997
2081
|
|
|
1998
2082
|
/**
|
|
1999
2083
|
* Access the result of the root loader from a React component.
|
|
@@ -2104,7 +2188,6 @@
|
|
|
2104
2188
|
### Patch Changes
|
|
2105
2189
|
|
|
2106
2190
|
- Improve performance of predictive search: ([#1823](https://github.com/Shopify/hydrogen/pull/1823)) by [@frandiox](https://github.com/frandiox)
|
|
2107
|
-
|
|
2108
2191
|
- Change the request to be GET instead of POST to avoid Remix route revalidations.
|
|
2109
2192
|
- Add Cache-Control headers to the response to get quicker results when typing.
|
|
2110
2193
|
|
|
@@ -2155,10 +2238,10 @@
|
|
|
2155
2238
|
- This is an important fix to a bug with 404 routes and path-based i18n projects where some unknown routes would not properly render a 404. This fixes all new projects, but to fix existing projects, add a `($locale).tsx` route with the following contents: ([#1732](https://github.com/Shopify/hydrogen/pull/1732)) by [@blittle](https://github.com/blittle)
|
|
2156
2239
|
|
|
2157
2240
|
```ts
|
|
2158
|
-
import {
|
|
2241
|
+
import {type LoaderFunctionArgs} from '@remix-run/server-runtime';
|
|
2159
2242
|
|
|
2160
|
-
export async function loader({
|
|
2161
|
-
const {
|
|
2243
|
+
export async function loader({params, context}: LoaderFunctionArgs) {
|
|
2244
|
+
const {language, country} = context.storefront.i18n;
|
|
2162
2245
|
|
|
2163
2246
|
if (
|
|
2164
2247
|
params.locale &&
|
|
@@ -2166,7 +2249,7 @@
|
|
|
2166
2249
|
) {
|
|
2167
2250
|
// If the locale URL param is defined, yet we still are still at the default locale
|
|
2168
2251
|
// then the the locale param must be invalid, send to the 404 page
|
|
2169
|
-
throw new Response(null, {
|
|
2252
|
+
throw new Response(null, {status: 404});
|
|
2170
2253
|
}
|
|
2171
2254
|
|
|
2172
2255
|
return null;
|
|
@@ -2222,11 +2305,11 @@
|
|
|
2222
2305
|
```yaml
|
|
2223
2306
|
projects:
|
|
2224
2307
|
default:
|
|
2225
|
-
schema:
|
|
2308
|
+
schema: 'node_modules/@shopify/hydrogen/storefront.schema.json'
|
|
2226
2309
|
documents:
|
|
2227
|
-
-
|
|
2228
|
-
-
|
|
2229
|
-
-
|
|
2310
|
+
- '!*.d.ts'
|
|
2311
|
+
- '*.{ts,tsx,js,jsx}'
|
|
2312
|
+
- 'app/**/*.{ts,tsx,js,jsx}'
|
|
2230
2313
|
```
|
|
2231
2314
|
|
|
2232
2315
|
- Improve resiliency of `HydrogenSession` ([#1583](https://github.com/Shopify/hydrogen/pull/1583)) by [@blittle](https://github.com/blittle)
|
|
@@ -2324,7 +2407,6 @@
|
|
|
2324
2407
|
### Major Changes
|
|
2325
2408
|
|
|
2326
2409
|
- The Storefront API 2023-10 now returns menu item URLs that include the `primaryDomainUrl`, instead of defaulting to the Shopify store ID URL (example.myshopify.com). The skeleton template requires changes to check for the `primaryDomainUrl`: by [@blittle](https://github.com/blittle)
|
|
2327
|
-
|
|
2328
2410
|
1. Update the `HeaderMenu` component to accept a `primaryDomainUrl` and include
|
|
2329
2411
|
it in the internal url check
|
|
2330
2412
|
|
|
@@ -2441,8 +2523,8 @@
|
|
|
2441
2523
|
```ts
|
|
2442
2524
|
// root.tsx
|
|
2443
2525
|
|
|
2444
|
-
import {
|
|
2445
|
-
import {
|
|
2526
|
+
import {useMatches} from '@remix-run/react';
|
|
2527
|
+
import {type SerializeFrom} from '@shopify/remix-oxygen';
|
|
2446
2528
|
|
|
2447
2529
|
export const useRootLoaderData = () => {
|
|
2448
2530
|
const [root] = useMatches();
|
|
@@ -2,7 +2,7 @@ import type {CartLineUpdateInput} from '@shopify/hydrogen/storefront-api-types';
|
|
|
2
2
|
import type {CartLayout} from '~/components/CartMain';
|
|
3
3
|
import {CartForm, Image, type OptimisticCartLine} from '@shopify/hydrogen';
|
|
4
4
|
import {useVariantUrl} from '~/lib/variants';
|
|
5
|
-
import {
|
|
5
|
+
import {Link} from 'react-router';
|
|
6
6
|
import {ProductPrice} from './ProductPrice';
|
|
7
7
|
import {useAside} from './Aside';
|
|
8
8
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {useOptimisticCart} from '@shopify/hydrogen';
|
|
2
|
-
import {
|
|
2
|
+
import {Link} from 'react-router';
|
|
3
3
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
4
4
|
import {useAside} from '~/components/Aside';
|
|
5
5
|
import {CartLineItem} from '~/components/CartLineItem';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
2
2
|
import type {CartLayout} from '~/components/CartMain';
|
|
3
3
|
import {CartForm, Money, type OptimisticCart} from '@shopify/hydrogen';
|
|
4
|
-
import {useRef} from 'react';
|
|
5
|
-
import {
|
|
4
|
+
import {useEffect, useRef} from 'react';
|
|
5
|
+
import {useFetcher} from 'react-router';
|
|
6
|
+
import type {FetcherWithComponents} from 'react-router';
|
|
6
7
|
|
|
7
8
|
type CartSummaryProps = {
|
|
8
9
|
cart: OptimisticCart<CartApiQueryFragment | null>;
|
|
@@ -19,19 +20,20 @@ export function CartSummary({cart, layout}: CartSummaryProps) {
|
|
|
19
20
|
<dl className="cart-subtotal">
|
|
20
21
|
<dt>Subtotal</dt>
|
|
21
22
|
<dd>
|
|
22
|
-
{cart
|
|
23
|
-
<Money data={cart
|
|
23
|
+
{cart?.cost?.subtotalAmount?.amount ? (
|
|
24
|
+
<Money data={cart?.cost?.subtotalAmount} />
|
|
24
25
|
) : (
|
|
25
26
|
'-'
|
|
26
27
|
)}
|
|
27
28
|
</dd>
|
|
28
29
|
</dl>
|
|
29
|
-
<CartDiscounts discountCodes={cart
|
|
30
|
-
<CartGiftCard giftCardCodes={cart
|
|
31
|
-
<CartCheckoutActions checkoutUrl={cart
|
|
30
|
+
<CartDiscounts discountCodes={cart?.discountCodes} />
|
|
31
|
+
<CartGiftCard giftCardCodes={cart?.appliedGiftCards} />
|
|
32
|
+
<CartCheckoutActions checkoutUrl={cart?.checkoutUrl} />
|
|
32
33
|
</div>
|
|
33
34
|
);
|
|
34
35
|
}
|
|
36
|
+
|
|
35
37
|
function CartCheckoutActions({checkoutUrl}: {checkoutUrl?: string}) {
|
|
36
38
|
if (!checkoutUrl) return null;
|
|
37
39
|
|
|
@@ -110,41 +112,47 @@ function CartGiftCard({
|
|
|
110
112
|
}) {
|
|
111
113
|
const appliedGiftCardCodes = useRef<string[]>([]);
|
|
112
114
|
const giftCardCodeInput = useRef<HTMLInputElement>(null);
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
+
const giftCardAddFetcher = useFetcher({key: 'gift-card-add'});
|
|
116
|
+
|
|
117
|
+
// Clear the gift card code input after the gift card is added
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (giftCardAddFetcher.data) {
|
|
120
|
+
giftCardCodeInput.current!.value = '';
|
|
121
|
+
}
|
|
122
|
+
}, [giftCardAddFetcher.data]);
|
|
115
123
|
|
|
116
124
|
function saveAppliedCode(code: string) {
|
|
117
125
|
const formattedCode = code.replace(/\s/g, ''); // Remove spaces
|
|
118
126
|
if (!appliedGiftCardCodes.current.includes(formattedCode)) {
|
|
119
127
|
appliedGiftCardCodes.current.push(formattedCode);
|
|
120
128
|
}
|
|
121
|
-
giftCardCodeInput.current!.value = '';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function removeAppliedCode() {
|
|
125
|
-
appliedGiftCardCodes.current = [];
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
return (
|
|
129
132
|
<div>
|
|
130
|
-
{/*
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
+
{/* Display applied gift cards with individual remove buttons */}
|
|
134
|
+
{giftCardCodes && giftCardCodes.length > 0 && (
|
|
135
|
+
<dl>
|
|
133
136
|
<dt>Applied Gift Card(s)</dt>
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
{giftCardCodes.map((giftCard) => (
|
|
138
|
+
<RemoveGiftCardForm key={giftCard.id} giftCardId={giftCard.id}>
|
|
139
|
+
<div className="cart-discount">
|
|
140
|
+
<code>***{giftCard.lastCharacters}</code>
|
|
141
|
+
|
|
142
|
+
<Money data={giftCard.amountUsed} />
|
|
143
|
+
|
|
144
|
+
<button type="submit">Remove</button>
|
|
145
|
+
</div>
|
|
146
|
+
</RemoveGiftCardForm>
|
|
147
|
+
))}
|
|
148
|
+
</dl>
|
|
149
|
+
)}
|
|
143
150
|
|
|
144
|
-
{/* Show an input to apply a
|
|
151
|
+
{/* Show an input to apply a gift card */}
|
|
145
152
|
<UpdateGiftCardForm
|
|
146
153
|
giftCardCodes={appliedGiftCardCodes.current}
|
|
147
154
|
saveAppliedCode={saveAppliedCode}
|
|
155
|
+
fetcherKey="gift-card-add"
|
|
148
156
|
>
|
|
149
157
|
<div>
|
|
150
158
|
<input
|
|
@@ -154,7 +162,9 @@ function CartGiftCard({
|
|
|
154
162
|
ref={giftCardCodeInput}
|
|
155
163
|
/>
|
|
156
164
|
|
|
157
|
-
<button type="submit">
|
|
165
|
+
<button type="submit" disabled={giftCardAddFetcher.state !== 'idle'}>
|
|
166
|
+
Apply
|
|
167
|
+
</button>
|
|
158
168
|
</div>
|
|
159
169
|
</UpdateGiftCardForm>
|
|
160
170
|
</div>
|
|
@@ -164,15 +174,17 @@ function CartGiftCard({
|
|
|
164
174
|
function UpdateGiftCardForm({
|
|
165
175
|
giftCardCodes,
|
|
166
176
|
saveAppliedCode,
|
|
177
|
+
fetcherKey,
|
|
167
178
|
children,
|
|
168
179
|
}: {
|
|
169
180
|
giftCardCodes?: string[];
|
|
170
181
|
saveAppliedCode?: (code: string) => void;
|
|
171
|
-
|
|
182
|
+
fetcherKey?: string;
|
|
172
183
|
children: React.ReactNode;
|
|
173
184
|
}) {
|
|
174
185
|
return (
|
|
175
186
|
<CartForm
|
|
187
|
+
fetcherKey={fetcherKey}
|
|
176
188
|
route="/cart"
|
|
177
189
|
action={CartForm.ACTIONS.GiftCardCodesUpdate}
|
|
178
190
|
inputs={{
|
|
@@ -189,3 +201,24 @@ function UpdateGiftCardForm({
|
|
|
189
201
|
</CartForm>
|
|
190
202
|
);
|
|
191
203
|
}
|
|
204
|
+
|
|
205
|
+
function RemoveGiftCardForm({
|
|
206
|
+
giftCardId,
|
|
207
|
+
children,
|
|
208
|
+
}: {
|
|
209
|
+
giftCardId: string;
|
|
210
|
+
children: React.ReactNode;
|
|
211
|
+
}) {
|
|
212
|
+
return (
|
|
213
|
+
<CartForm
|
|
214
|
+
route="/cart"
|
|
215
|
+
action={CartForm.ACTIONS.GiftCardCodesRemove}
|
|
216
|
+
inputs={{
|
|
217
|
+
giftCardCodes: [giftCardId],
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
{children}
|
|
221
|
+
</CartForm>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Link, useNavigate} from 'react-router';
|
|
2
2
|
import {type MappedProductOptions} from '@shopify/hydrogen';
|
|
3
3
|
import type {
|
|
4
4
|
Maybe,
|
|
@@ -84,7 +84,7 @@ export function ProductForm({
|
|
|
84
84
|
disabled={!exists}
|
|
85
85
|
onClick={() => {
|
|
86
86
|
if (!selected) {
|
|
87
|
-
navigate(`?${variantUriQuery}`, {
|
|
87
|
+
void navigate(`?${variantUriQuery}`, {
|
|
88
88
|
replace: true,
|
|
89
89
|
preventScrollReset: true,
|
|
90
90
|
});
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useFetcher,
|
|
3
|
+
useNavigate,
|
|
4
|
+
type FormProps,
|
|
5
|
+
type Fetcher,
|
|
6
|
+
} from 'react-router';
|
|
2
7
|
import React, {useRef, useEffect} from 'react';
|
|
3
8
|
import type {PredictiveSearchReturn} from '~/lib/search';
|
|
4
9
|
import {useAside} from './Aside';
|
|
@@ -41,13 +46,13 @@ export function SearchFormPredictive({
|
|
|
41
46
|
/** Navigate to the search page with the current input value */
|
|
42
47
|
function goToSearch() {
|
|
43
48
|
const term = inputRef?.current?.value;
|
|
44
|
-
navigate(SEARCH_ENDPOINT + (term ? `?q=${term}` : ''));
|
|
49
|
+
void navigate(SEARCH_ENDPOINT + (term ? `?q=${term}` : ''));
|
|
45
50
|
aside.close();
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
/** Fetch search results based on the input value */
|
|
49
54
|
function fetchResults(event: React.ChangeEvent<HTMLInputElement>) {
|
|
50
|
-
fetcher.submit(
|
|
55
|
+
void fetcher.submit(
|
|
51
56
|
{q: event.target.value || '', limit: 5, predictive: true},
|
|
52
57
|
{method: 'GET', action: SEARCH_ENDPOINT},
|
|
53
58
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Link} from 'react-router';
|
|
2
2
|
import {Image, Money, Pagination} from '@shopify/hydrogen';
|
|
3
3
|
import {urlWithTrackingParams, type RegularSearchReturn} from '~/lib/search';
|
|
4
4
|
|
|
@@ -120,19 +120,11 @@ function SearchResultsProducts({
|
|
|
120
120
|
<div className="search-results-item" key={product.id}>
|
|
121
121
|
<Link prefetch="intent" to={productUrl}>
|
|
122
122
|
{image && (
|
|
123
|
-
<Image
|
|
124
|
-
data={image}
|
|
125
|
-
alt={product.title}
|
|
126
|
-
width={50}
|
|
127
|
-
/>
|
|
123
|
+
<Image data={image} alt={product.title} width={50} />
|
|
128
124
|
)}
|
|
129
125
|
<div>
|
|
130
126
|
<p>{product.title}</p>
|
|
131
|
-
<small>
|
|
132
|
-
{price &&
|
|
133
|
-
<Money data={price} />
|
|
134
|
-
}
|
|
135
|
-
</small>
|
|
127
|
+
<small>{price && <Money data={price} />}</small>
|
|
136
128
|
</div>
|
|
137
129
|
</Link>
|
|
138
130
|
</div>
|