@shopify/cli-hydrogen 12.0.0 → 12.0.2
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/README.md +1 -1
- package/dist/assets/hydrogen/routes/locale-check.ts +3 -3
- package/dist/assets/hydrogen/starter/.graphqlrc.ts +4 -2
- package/dist/assets/hydrogen/starter/CHANGELOG.md +278 -0
- package/dist/assets/hydrogen/starter/app/components/Aside.tsx +4 -2
- package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +67 -38
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +49 -8
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +133 -57
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +3 -3
- package/dist/assets/hydrogen/starter/app/components/MockShopNotice.tsx +20 -0
- package/dist/assets/hydrogen/starter/app/components/PaginatedResourceSection.tsx +24 -4
- package/dist/assets/hydrogen/starter/app/components/ProductPrice.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/entry.client.tsx +2 -3
- package/dist/assets/hydrogen/starter/app/lib/context.ts +5 -0
- package/dist/assets/hydrogen/starter/app/lib/fragments.ts +8 -0
- package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +14 -53
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +15 -9
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +14 -14
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.tsx +4 -7
- package/dist/assets/hydrogen/starter/app/routes/account_.login.tsx +10 -0
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +2 -9
- package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +1 -4
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +3 -11
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +1 -3
- package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +2 -8
- package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +1 -4
- package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +2 -9
- package/dist/assets/hydrogen/starter/app/routes/search.tsx +18 -12
- package/dist/assets/hydrogen/starter/app/styles/app.css +72 -1
- package/dist/assets/hydrogen/starter/eslint.config.js +1 -0
- package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +3 -3
- package/dist/assets/hydrogen/starter/guides/search/search.md +1 -1
- package/dist/assets/hydrogen/starter/package.json +16 -16
- package/dist/assets/hydrogen/starter/server.ts +5 -7
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +89 -11
- package/dist/assets/hydrogen/starter/vite.config.ts +10 -4
- package/dist/assets/hydrogen/vite/package.json +1 -2
- package/dist/assets/hydrogen/vite/vite.config.js +4 -3
- package/dist/commands/hydrogen/deploy.js +19 -13
- package/dist/commands/hydrogen/dev.js +6 -6
- package/dist/commands/hydrogen/generate/route.js +1 -1
- package/dist/commands/hydrogen/init.d.ts +2 -4
- package/dist/commands/hydrogen/init.js +2 -8
- package/dist/commands/hydrogen/preview.js +1 -1
- package/dist/commands/hydrogen/setup/css.js +1 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -1
- package/dist/commands/hydrogen/setup/vite.js +1 -1
- package/dist/commands/hydrogen/setup.js +31 -33
- package/dist/commands/hydrogen/upgrade.js +173 -39
- package/dist/lib/build.js +4 -5
- package/dist/lib/bundle/vite-plugin.js +7 -21
- package/dist/lib/check-lockfile.js +16 -7
- package/dist/lib/codegen.js +2 -2
- package/dist/lib/format-code.js +3 -3
- package/dist/lib/graphql/admin/client.js +48 -23
- package/dist/lib/import-utils.js +20 -4
- package/dist/lib/mini-oxygen/workerd.js +3 -5
- package/dist/lib/onboarding/common.js +21 -26
- package/dist/lib/onboarding/local.js +46 -59
- package/dist/lib/package-managers.js +2 -0
- package/dist/lib/patch-cli.js +198 -0
- package/dist/lib/setups/routes/generate.js +5 -3
- package/dist/lib/template-pack.js +93 -0
- package/dist/lib/transpile/morph/functions.js +1 -1
- package/dist/lib/transpile/morph/typedefs.js +2 -3
- package/dist/lib/upgrade-e2e-utils.js +50 -0
- package/oclif.manifest.json +7 -15
- package/package.json +22 -19
- package/dist/assets/hydrogen/starter/app/routes/api.$version.[graphql.json].tsx +0 -14
- package/dist/lib/react-router-version-check.js +0 -82
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ The Hydrogen extension for the [Shopify CLI](https://shopify.dev/apps/tools/cli)
|
|
|
8
8
|
|
|
9
9
|
The most common way to test the cli changes locally is to do the following:
|
|
10
10
|
|
|
11
|
-
- Run `
|
|
11
|
+
- Run `pnpm run build` in this directory (`packages/cli` from the root of the repo).
|
|
12
12
|
- Run `npx shopify hydrogen` anywhere else in the monorepo, for example `npx shopify hydrogen init`.
|
|
13
13
|
- If you want to test a command inside of a template, run the command from within that template or use the `--path` flag to point to another template or any Hydrogen app.
|
|
14
14
|
- If you want to make changes to a file that is generated when running `npx shopify hydrogen generate`, make changes to that file from inside of the `templates/skeleton` directory.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {LoaderFunctionArgs} from '
|
|
1
|
+
import type {LoaderFunctionArgs} from 'react-router';
|
|
2
2
|
|
|
3
3
|
export async function loader({params, context}: LoaderFunctionArgs) {
|
|
4
4
|
const {language, country} = context.storefront.i18n;
|
|
@@ -7,8 +7,8 @@ export async function loader({params, context}: LoaderFunctionArgs) {
|
|
|
7
7
|
params.locale &&
|
|
8
8
|
params.locale.toLowerCase() !== `${language}-${country}`.toLowerCase()
|
|
9
9
|
) {
|
|
10
|
-
// If the locale URL param is defined, yet we
|
|
11
|
-
// then the
|
|
10
|
+
// If the locale URL param is defined, yet we are still at the default locale
|
|
11
|
+
// then the locale param must be invalid, send to the 404 page
|
|
12
12
|
throw new Response(null, {status: 404});
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -6,7 +6,7 @@ import {getSchema} from '@shopify/hydrogen-codegen';
|
|
|
6
6
|
* @see https://the-guild.dev/graphql/config/docs/user/usage
|
|
7
7
|
* @type {IGraphQLConfig}
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
const graphqlConfig: IGraphQLConfig = {
|
|
10
10
|
projects: {
|
|
11
11
|
default: {
|
|
12
12
|
schema: getSchema('storefront'),
|
|
@@ -24,4 +24,6 @@ export default {
|
|
|
24
24
|
|
|
25
25
|
// Add your own GraphQL projects here for CMS, Shopify Admin API, etc.
|
|
26
26
|
},
|
|
27
|
-
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default graphqlConfig;
|
|
@@ -1,5 +1,283 @@
|
|
|
1
1
|
# skeleton
|
|
2
2
|
|
|
3
|
+
## 2026.4.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`23431c956193420bce3442e9e5cc711dc95cc497`](https://github.com/Shopify/hydrogen/commit/23431c956193420bce3442e9e5cc711dc95cc497)]:
|
|
8
|
+
- @shopify/hydrogen@2026.4.4
|
|
9
|
+
|
|
10
|
+
## 2026.4.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Include line item children recursively in cart. ([#3753](https://github.com/Shopify/hydrogen/pull/3753)) by [@martin-pettersson](https://github.com/martin-pettersson)
|
|
15
|
+
|
|
16
|
+
- Add generic cart result typing to `createCartHandler` so custom cart fragments can use their generated fragment types. ([#3767](https://github.com/Shopify/hydrogen/pull/3767)) by [@andguy95](https://github.com/andguy95)
|
|
17
|
+
|
|
18
|
+
- Widen React Router peer dependency ranges so Hydrogen packages accept compatible React Router 7.16 patch versions without npm peer dependency conflicts. New Hydrogen projects now default to React Router 7.16.0. ([#3771](https://github.com/Shopify/hydrogen/pull/3771)) by [@fredericoo](https://github.com/fredericoo)
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`3ccc22e0a3407298e835104e29adfb036f261474`](https://github.com/Shopify/hydrogen/commit/3ccc22e0a3407298e835104e29adfb036f261474), [`a810db483c108ac8bbeaac45595b130ed95a2ec7`](https://github.com/Shopify/hydrogen/commit/a810db483c108ac8bbeaac45595b130ed95a2ec7), [`d17057eb4630710743e81b83573973100ec56d23`](https://github.com/Shopify/hydrogen/commit/d17057eb4630710743e81b83573973100ec56d23), [`995190036d99e02ba6fb559b8e3c406c90043599`](https://github.com/Shopify/hydrogen/commit/995190036d99e02ba6fb559b8e3c406c90043599), [`39f2b326e9fddda36b1d12149794bf4ffcc0d4b8`](https://github.com/Shopify/hydrogen/commit/39f2b326e9fddda36b1d12149794bf4ffcc0d4b8)]:
|
|
21
|
+
- @shopify/hydrogen@2026.4.3
|
|
22
|
+
|
|
23
|
+
## 2026.4.2
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Add support for Vite 7 and Vite 8. Hydrogen remains backwards-compatible with Vite 5+. ([#3617](https://github.com/Shopify/hydrogen/pull/3617)) by [@frandiox](https://github.com/frandiox)
|
|
28
|
+
|
|
29
|
+
Mini Oxygen's dev server has been refactored to use the [Vite Environment API](https://vite.dev/guide/api-environment), which is the standard way to run non-browser runtimes in Vite. This replaces the previous custom middleware approach with a first-class `FetchableDevEnvironment`, improving compatibility with Vite's built-in HMR and module invalidation.
|
|
30
|
+
|
|
31
|
+
New Hydrogen projects created with `npm create @shopify/hydrogen` will default to Vite 8. The `vite-tsconfig-paths` plugin is no longer needed in the skeleton template since Vite 8 supports `resolve.tsconfigPaths` natively.
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [[`dc49699c799997d5893bc06e444f888e86a3bc29`](https://github.com/Shopify/hydrogen/commit/dc49699c799997d5893bc06e444f888e86a3bc29), [`50df825c57159757529f5f9f62c258d4de2a4b97`](https://github.com/Shopify/hydrogen/commit/50df825c57159757529f5f9f62c258d4de2a4b97), [`51f1e77fe63be5e5ded4ef0c91942bc304f1abc4`](https://github.com/Shopify/hydrogen/commit/51f1e77fe63be5e5ded4ef0c91942bc304f1abc4)]:
|
|
34
|
+
- @shopify/hydrogen@2026.4.2
|
|
35
|
+
|
|
36
|
+
## 2026.4.1
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Fix `set-cookie-parser` and `cookie` resolution warnings during `dev` by using Vite's nested dependency syntax (`react-router > dep`). These are CJS transitive dependencies of `react-router` that weren't resolvable by bare name with strict package managers like pnpm. ([#3698](https://github.com/Shopify/hydrogen/pull/3698)) by [@fredericoo](https://github.com/fredericoo)
|
|
41
|
+
|
|
42
|
+
- Updated dependencies [[`f84ab400c62d89827574d0fa65ba310a2e75f36f`](https://github.com/Shopify/hydrogen/commit/f84ab400c62d89827574d0fa65ba310a2e75f36f)]:
|
|
43
|
+
- @shopify/hydrogen@2026.4.1
|
|
44
|
+
|
|
45
|
+
## 2026.4.0
|
|
46
|
+
|
|
47
|
+
### Major Changes
|
|
48
|
+
|
|
49
|
+
- Update Storefront API and Customer Account API from 2026-01 to 2026-04. ([#3651](https://github.com/Shopify/hydrogen/pull/3651)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
50
|
+
|
|
51
|
+
## Breaking changes
|
|
52
|
+
|
|
53
|
+
**JSON metafield values limited to 128KB**: When using API version 2026-04 or later, the Storefront API limits JSON type metafield writes to 128KB. This limit applies at the API level - Hydrogen passes through to the Storefront API without additional restriction. Apps that used JSON metafields before April 1, 2026 are grandfathered at the existing 2MB limit. Large metafield values continue to be readable by all API versions.
|
|
54
|
+
|
|
55
|
+
## New features
|
|
56
|
+
|
|
57
|
+
**New `MERCHANDISE_LINE_TRANSFORMERS_RUN_ERROR` cart error code**: Cart operations (`cartCreate`, `cartLinesAdd`, etc.) now return a specific `MERCHANDISE_LINE_TRANSFORMERS_RUN_ERROR` error code when a Cart Transform Function fails at runtime, instead of the previous generic `INVALID` error code. If you handle cart errors in your storefront code, you may want to add handling for this new code.
|
|
58
|
+
|
|
59
|
+
## Changelog links
|
|
60
|
+
- [Storefront API 2026-04 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-04&api_type=storefront-graphql)
|
|
61
|
+
- [Customer Account API 2026-04 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-04&api_type=customer-account-graphql)
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- Updated dependencies [[`e7215ed0d7a74cacfa8c935f414c1cf32fc2ccd0`](https://github.com/Shopify/hydrogen/commit/e7215ed0d7a74cacfa8c935f414c1cf32fc2ccd0), [`92ab8e8b59807bbdb5dbecaa18629292d5566135`](https://github.com/Shopify/hydrogen/commit/92ab8e8b59807bbdb5dbecaa18629292d5566135), [`b0caa5c013380c7837f049f48da089a1671e2c6d`](https://github.com/Shopify/hydrogen/commit/b0caa5c013380c7837f049f48da089a1671e2c6d)]:
|
|
66
|
+
- @shopify/hydrogen@2026.4.0
|
|
67
|
+
|
|
68
|
+
## 2026.1.4
|
|
69
|
+
|
|
70
|
+
### Patch Changes
|
|
71
|
+
|
|
72
|
+
- Remove redundant Storefront API proxy route from skeleton template. The server now automatically proxies requests to `/api/:version/graphql.json` via `createRequestHandler` with `proxyStandardRoutes: true` (enabled by default since December 2025). ([#3572](https://github.com/Shopify/hydrogen/pull/3572)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
73
|
+
|
|
74
|
+
Developers no longer need a manual route file for the tokenless Storefront API. Existing apps with this route can safely delete it - the server-level proxy provides the same functionality with better cookie forwarding and analytics integration.
|
|
75
|
+
|
|
76
|
+
- Updated dependencies [[`b0a75c1d759706931876f056662de2497cb3e688`](https://github.com/Shopify/hydrogen/commit/b0a75c1d759706931876f056662de2497cb3e688), [`a44ee3566b9bb9a7f43f05dfaae6f1f2ab1d548f`](https://github.com/Shopify/hydrogen/commit/a44ee3566b9bb9a7f43f05dfaae6f1f2ab1d548f)]:
|
|
77
|
+
- @shopify/hydrogen@2026.1.4
|
|
78
|
+
|
|
79
|
+
## 2026.1.3
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- Improve screen reader experience for paginated product grids by hiding decorative arrow characters from assistive technology. ([#3557](https://github.com/Shopify/hydrogen/pull/3557)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
84
|
+
|
|
85
|
+
- Fix broken `aria-label` on territory code input in address form. The label was the raw developer string `"territoryCode"` instead of a human-readable `"Country code"`. ([#3607](https://github.com/Shopify/hydrogen/pull/3607)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
86
|
+
|
|
87
|
+
- Add aria-label to ProductPrice for improved screen reader accessibility ([#3558](https://github.com/Shopify/hydrogen/pull/3558)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
88
|
+
|
|
89
|
+
- Updated dependencies [[`108243003a7f36349a446478f4e8ab0cade3e13a`](https://github.com/Shopify/hydrogen/commit/108243003a7f36349a446478f4e8ab0cade3e13a)]:
|
|
90
|
+
- @shopify/hydrogen@2026.1.3
|
|
91
|
+
|
|
92
|
+
## 2026.1.2
|
|
93
|
+
|
|
94
|
+
### Patch Changes
|
|
95
|
+
|
|
96
|
+
- Improve gift card accessibility in Skeleton template ([#3518](https://github.com/Shopify/hydrogen/pull/3518)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
97
|
+
|
|
98
|
+
- Updated shopify/cli dependencies for cli-hydrogen ([#3553](https://github.com/Shopify/hydrogen/pull/3553)) by [@andguy95](https://github.com/andguy95)
|
|
99
|
+
|
|
100
|
+
- Updated loaders that used `customerAccount.handleAuthStatus()` to now await it. ([#3523](https://github.com/Shopify/hydrogen/pull/3523)) by [@fredericoo](https://github.com/fredericoo)
|
|
101
|
+
|
|
102
|
+
### Migration
|
|
103
|
+
|
|
104
|
+
If you call `handleAuthStatus()` in your own loaders, update those callsites to use `await`.
|
|
105
|
+
|
|
106
|
+
- Updated dependencies [[`16b0e7baca0dfd1fb330d12dac924c7593d169a8`](https://github.com/Shopify/hydrogen/commit/16b0e7baca0dfd1fb330d12dac924c7593d169a8), [`1c19b87782818dbdb4252754d2d44eb9a44fe50f`](https://github.com/Shopify/hydrogen/commit/1c19b87782818dbdb4252754d2d44eb9a44fe50f), [`029fa2d0e2297f67b37c650ba8e875ee5dee81b3`](https://github.com/Shopify/hydrogen/commit/029fa2d0e2297f67b37c650ba8e875ee5dee81b3)]:
|
|
107
|
+
- @shopify/hydrogen@2026.1.2
|
|
108
|
+
|
|
109
|
+
## 2026.1.1
|
|
110
|
+
|
|
111
|
+
### Patch Changes
|
|
112
|
+
|
|
113
|
+
- Added a notice with relevant information on how to link a store in case there is no store linked yet ([#3448](https://github.com/Shopify/hydrogen/pull/3448)) by [@fredericoo](https://github.com/fredericoo)
|
|
114
|
+
|
|
115
|
+
- Fixed an issue where users without addresses could not add the first one ([#3456](https://github.com/Shopify/hydrogen/pull/3456)) by [@fredericoo](https://github.com/fredericoo)
|
|
116
|
+
|
|
117
|
+
- Updated dependencies [[`ff93a1daf2207e52e1f8331f9ff2ccd1f9b7fed6`](https://github.com/Shopify/hydrogen/commit/ff93a1daf2207e52e1f8331f9ff2ccd1f9b7fed6)]:
|
|
118
|
+
- @shopify/hydrogen@2026.1.1
|
|
119
|
+
|
|
120
|
+
## 2026.1.0
|
|
121
|
+
|
|
122
|
+
### Major Changes
|
|
123
|
+
|
|
124
|
+
- Updated to Storefront API 2026-01 and Customer Account API 2026-01. ([#3434](https://github.com/Shopify/hydrogen/pull/3434)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
125
|
+
|
|
126
|
+
This is a quarterly API version update aligned with Shopify's API release schedule.
|
|
127
|
+
|
|
128
|
+
**Action Required**: The `cartDiscountCodesUpdate` mutation now requires the `discountCodes` argument. If you have custom cart discount code logic, verify your mutations include this field.
|
|
129
|
+
|
|
130
|
+
Review the changelogs for other changes that may affect your storefront:
|
|
131
|
+
- [Storefront API 2026-01 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-01&api_type=storefront-graphql)
|
|
132
|
+
- [Customer Account API 2026-01 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-01&api_type=customer-account-graphql)
|
|
133
|
+
|
|
134
|
+
### Patch Changes
|
|
135
|
+
|
|
136
|
+
- Updated dependencies [[`d46c8864aea059cac7dda4871a565f76a04b1495`](https://github.com/Shopify/hydrogen/commit/d46c8864aea059cac7dda4871a565f76a04b1495)]:
|
|
137
|
+
- @shopify/hydrogen@2026.0.0
|
|
138
|
+
|
|
139
|
+
## 2025.10.1
|
|
140
|
+
|
|
141
|
+
### Major Changes
|
|
142
|
+
|
|
143
|
+
- Update Storefront API and Customer Account API to version 2025-10 ([#3430](https://github.com/Shopify/hydrogen/pull/3430)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
144
|
+
|
|
145
|
+
### Patch Changes
|
|
146
|
+
|
|
147
|
+
- Add support for Bun's text-based lockfile (`bun.lock`) introduced in Bun 1.2, and npm's shrinkwrap lockfile (`npm-shrinkwrap.json`), as alternatives to their respective primary lockfiles (`bun.lockb` and `package-lock.json`). ([#3430](https://github.com/Shopify/hydrogen/pull/3430)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
148
|
+
|
|
149
|
+
- Add `cartGiftCardCodesAdd` mutation ([#3430](https://github.com/Shopify/hydrogen/pull/3430)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
150
|
+
|
|
151
|
+
## New Feature: cartGiftCardCodesAdd
|
|
152
|
+
|
|
153
|
+
The skeleton template has been updated to use the new `cartGiftCardCodesAdd` mutation:
|
|
154
|
+
- Removed `UpdateGiftCardForm` component from `CartSummary.tsx`
|
|
155
|
+
- Added `AddGiftCardForm` component using `CartForm.ACTIONS.GiftCardCodesAdd`
|
|
156
|
+
|
|
157
|
+
If you customized the gift card form in your project, you may want to migrate to the new `Add` action for simpler code.
|
|
158
|
+
|
|
159
|
+
## Usage
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import {CartForm} from '@shopify/hydrogen';
|
|
163
|
+
|
|
164
|
+
<CartForm action={CartForm.ACTIONS.GiftCardCodesAdd} inputs={{giftCardCodes: ['CODE1', 'CODE2']}}>
|
|
165
|
+
<button>Add Gift Cards</button>
|
|
166
|
+
</CartForm>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Or with createCartHandler:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const cart = createCartHandler({storefront, getCartId, setCartId});
|
|
173
|
+
await cart.addGiftCardCodes(['SUMMER2025', 'WELCOME10']);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- Add support for nested cart line items (warranties, gift wrapping, etc.) ([#3430](https://github.com/Shopify/hydrogen/pull/3430)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
177
|
+
|
|
178
|
+
Storefront API 2025-10 introduces `parentRelationship` on cart line items, enabling parent-child relationships for add-ons. This update displays nested line items in the cart.
|
|
179
|
+
|
|
180
|
+
### Changes
|
|
181
|
+
- Updates GraphQL fragments to include `parentRelationship` and `lineComponents` fields
|
|
182
|
+
- Updates `CartMain` and `CartLineItem` to render child line items with visual hierarchy
|
|
183
|
+
|
|
184
|
+
### Note
|
|
185
|
+
|
|
186
|
+
This update focuses on **displaying** nested line items. To add both a product and its child (e.g., warranty) in a single action:
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<AddToCartButton
|
|
190
|
+
lines={[
|
|
191
|
+
{merchandiseId: 'gid://shopify/ProductVariant/laptop-456', quantity: 1},
|
|
192
|
+
{
|
|
193
|
+
merchandiseId: 'gid://shopify/ProductVariant/warranty-123',
|
|
194
|
+
quantity: 1,
|
|
195
|
+
parent: {merchandiseId: 'gid://shopify/ProductVariant/laptop-456'},
|
|
196
|
+
},
|
|
197
|
+
]}
|
|
198
|
+
>
|
|
199
|
+
Add to Cart with Warranty
|
|
200
|
+
</AddToCartButton>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
- Updated dependencies [[`722915130410086bc7af22215ba57ee77aa14156`](https://github.com/Shopify/hydrogen/commit/722915130410086bc7af22215ba57ee77aa14156)]:
|
|
204
|
+
- @shopify/hydrogen@2025.10.1
|
|
205
|
+
|
|
206
|
+
## 2025.10.0
|
|
207
|
+
|
|
208
|
+
### Patch Changes
|
|
209
|
+
|
|
210
|
+
- Updated dependencies [[`cd653456fbd1e7e1ab1f6fecff04c89a74b6cad9`](https://github.com/Shopify/hydrogen/commit/cd653456fbd1e7e1ab1f6fecff04c89a74b6cad9), [`24d26ad94e90ab0a859c274838f7f31e75a7808c`](https://github.com/Shopify/hydrogen/commit/24d26ad94e90ab0a859c274838f7f31e75a7808c), [`13a6f8987ea20d33a30a9c0329d7c11528b892ea`](https://github.com/Shopify/hydrogen/commit/13a6f8987ea20d33a30a9c0329d7c11528b892ea), [`403c1f5b6e266c3dfad30f7cfed229e3304570b0`](https://github.com/Shopify/hydrogen/commit/403c1f5b6e266c3dfad30f7cfed229e3304570b0), [`38f8a79625838a9cd4520b20c0db2e5d331f7d26`](https://github.com/Shopify/hydrogen/commit/38f8a79625838a9cd4520b20c0db2e5d331f7d26)]:
|
|
211
|
+
- @shopify/hydrogen@2026.0.0
|
|
212
|
+
|
|
213
|
+
## 2025.7.3
|
|
214
|
+
|
|
215
|
+
### Patch Changes
|
|
216
|
+
|
|
217
|
+
- Support OAuth parameters via URL query strings in skeleton login route ([#3391](https://github.com/Shopify/hydrogen/pull/3391)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
218
|
+
|
|
219
|
+
The skeleton template's login route (`account_.login.tsx`) now reads OAuth parameters from the URL and forwards them to `customerAccount.login()`. This enables deep linking to the login page with pre-configured authentication options.
|
|
220
|
+
|
|
221
|
+
### Supported Query Parameters
|
|
222
|
+
|
|
223
|
+
| Query Parameter | Description |
|
|
224
|
+
| ----------------- | ---------------------------------------------------------------------------------- |
|
|
225
|
+
| `acr_values` | Direct users to a specific login method (e.g., `provider:google` for social login) |
|
|
226
|
+
| `login_hint` | Pre-fill the email address field |
|
|
227
|
+
| `login_hint_mode` | When set to `submit` with `login_hint`, auto-submits the login form |
|
|
228
|
+
| `locale` | Display the login page in a specific language (e.g., `fr`, `zh-CN`) |
|
|
229
|
+
|
|
230
|
+
### Usage Examples
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
/account/login?login_hint=user@example.com
|
|
234
|
+
/account/login?login_hint=user@example.com&login_hint_mode=submit
|
|
235
|
+
/account/login?acr_values=provider:google
|
|
236
|
+
/account/login?locale=fr
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
- Updated dependencies [[`7c077f5f21a595c0355873ac8073b716dfeaf4d0`](https://github.com/Shopify/hydrogen/commit/7c077f5f21a595c0355873ac8073b716dfeaf4d0), [`7c077f5f21a595c0355873ac8073b716dfeaf4d0`](https://github.com/Shopify/hydrogen/commit/7c077f5f21a595c0355873ac8073b716dfeaf4d0), [`7c077f5f21a595c0355873ac8073b716dfeaf4d0`](https://github.com/Shopify/hydrogen/commit/7c077f5f21a595c0355873ac8073b716dfeaf4d0)]:
|
|
240
|
+
- @shopify/hydrogen@2025.8.0
|
|
241
|
+
|
|
242
|
+
## 2025.7.2
|
|
243
|
+
|
|
244
|
+
### Patch Changes
|
|
245
|
+
|
|
246
|
+
- Updated dependencies [[`6d22e45d29e89a7a8dddfe3c06459d89e4590483`](https://github.com/Shopify/hydrogen/commit/6d22e45d29e89a7a8dddfe3c06459d89e4590483), [`702f966c8e60eba7434363c9012f12bed92a8e4d`](https://github.com/Shopify/hydrogen/commit/702f966c8e60eba7434363c9012f12bed92a8e4d)]:
|
|
247
|
+
- @shopify/hydrogen@2025.7.2
|
|
248
|
+
|
|
249
|
+
## 2025.7.1
|
|
250
|
+
|
|
251
|
+
### Patch Changes
|
|
252
|
+
|
|
253
|
+
- Update React Router to 7.12.0 with stabilized future flags ([#3346](https://github.com/Shopify/hydrogen/pull/3346)) by [@kdaviduik](https://github.com/kdaviduik)
|
|
254
|
+
|
|
255
|
+
This release uses React Router's newly stabilized future flags (`v8_splitRouteModules`, `v8_middleware`) instead of their unstable counterparts
|
|
256
|
+
|
|
257
|
+
- Moved server build in `server.ts` from a dynamic import to a static import to speed up first rendering during local development (2s => 200ms). ([#3331](https://github.com/Shopify/hydrogen/pull/3331)) by [@frandiox](https://github.com/frandiox)
|
|
258
|
+
|
|
259
|
+
```diff
|
|
260
|
+
// server.ts
|
|
261
|
+
|
|
262
|
+
+import * as serverBuild from 'virtual:react-router/server-build';
|
|
263
|
+
|
|
264
|
+
const handleRequest = createRequestHandler({
|
|
265
|
+
- build: await import('virtual:react-router/server-build'),
|
|
266
|
+
+ build: serverBuild,
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Updated ESLint config to allow `virtual:` imports:
|
|
270
|
+
|
|
271
|
+
```diff
|
|
272
|
+
// eslint.config.js
|
|
273
|
+
|
|
274
|
+
rules: {
|
|
275
|
+
+ 'import/no-unresolved': ['error', {ignore: ['^virtual:']}],
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
- Updated dependencies [[`264e13349168f17cc1f096c84135d13d38cfc8df`](https://github.com/Shopify/hydrogen/commit/264e13349168f17cc1f096c84135d13d38cfc8df), [`6d5e3d371e7e02e15be17029a0f34daae53a978e`](https://github.com/Shopify/hydrogen/commit/6d5e3d371e7e02e15be17029a0f34daae53a978e), [`ee00f1025867c40d5f67fa89d4ffb215bf280e8f`](https://github.com/Shopify/hydrogen/commit/ee00f1025867c40d5f67fa89d4ffb215bf280e8f), [`5a38948133766e358c5f357f52562f6fdcfe7969`](https://github.com/Shopify/hydrogen/commit/5a38948133766e358c5f357f52562f6fdcfe7969), [`264e13349168f17cc1f096c84135d13d38cfc8df`](https://github.com/Shopify/hydrogen/commit/264e13349168f17cc1f096c84135d13d38cfc8df)]:
|
|
279
|
+
- @shopify/hydrogen@2025.7.1
|
|
280
|
+
|
|
3
281
|
## 2025.7.0
|
|
4
282
|
|
|
5
283
|
### Major Changes
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
useEffect,
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
|
+
import {useId} from 'react';
|
|
8
9
|
|
|
9
10
|
type AsideType = 'search' | 'cart' | 'mobile' | 'closed';
|
|
10
11
|
type AsideContextValue = {
|
|
@@ -34,7 +35,7 @@ export function Aside({
|
|
|
34
35
|
}) {
|
|
35
36
|
const {type: activeType, close} = useAside();
|
|
36
37
|
const expanded = type === activeType;
|
|
37
|
-
|
|
38
|
+
const id = useId();
|
|
38
39
|
useEffect(() => {
|
|
39
40
|
const abortController = new AbortController();
|
|
40
41
|
|
|
@@ -57,11 +58,12 @@ export function Aside({
|
|
|
57
58
|
aria-modal
|
|
58
59
|
className={`overlay ${expanded ? 'expanded' : ''}`}
|
|
59
60
|
role="dialog"
|
|
61
|
+
aria-labelledby={id}
|
|
60
62
|
>
|
|
61
63
|
<button className="close-outside" onClick={close} />
|
|
62
64
|
<aside>
|
|
63
65
|
<header>
|
|
64
|
-
<h3>{heading}</h3>
|
|
66
|
+
<h3 id={id}>{heading}</h3>
|
|
65
67
|
<button className="close reset" onClick={close} aria-label="Close">
|
|
66
68
|
×
|
|
67
69
|
</button>
|
|
@@ -1,69 +1,98 @@
|
|
|
1
1
|
import type {CartLineUpdateInput} from '@shopify/hydrogen/storefront-api-types';
|
|
2
|
-
import type {CartLayout} from '~/components/CartMain';
|
|
2
|
+
import type {CartLayout, LineItemChildrenMap} from '~/components/CartMain';
|
|
3
3
|
import {CartForm, Image, type OptimisticCartLine} from '@shopify/hydrogen';
|
|
4
4
|
import {useVariantUrl} from '~/lib/variants';
|
|
5
5
|
import {Link} from 'react-router';
|
|
6
6
|
import {ProductPrice} from './ProductPrice';
|
|
7
7
|
import {useAside} from './Aside';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
CartApiQueryFragment,
|
|
10
|
+
CartLineFragment,
|
|
11
|
+
} from 'storefrontapi.generated';
|
|
9
12
|
|
|
10
|
-
type CartLine = OptimisticCartLine<CartApiQueryFragment>;
|
|
13
|
+
export type CartLine = OptimisticCartLine<CartApiQueryFragment>;
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* A single line item in the cart. It displays the product image, title, price.
|
|
14
17
|
* It also provides controls to update the quantity or remove the line item.
|
|
18
|
+
* If the line is a parent line that has child components (like warranties or gift wrapping), they are
|
|
19
|
+
* rendered nested below the parent line.
|
|
15
20
|
*/
|
|
16
21
|
export function CartLineItem({
|
|
17
22
|
layout,
|
|
18
23
|
line,
|
|
24
|
+
childrenMap,
|
|
19
25
|
}: {
|
|
20
26
|
layout: CartLayout;
|
|
21
27
|
line: CartLine;
|
|
28
|
+
childrenMap: LineItemChildrenMap;
|
|
22
29
|
}) {
|
|
23
30
|
const {id, merchandise} = line;
|
|
24
31
|
const {product, title, image, selectedOptions} = merchandise;
|
|
25
32
|
const lineItemUrl = useVariantUrl(product.handle, selectedOptions);
|
|
26
33
|
const {close} = useAside();
|
|
34
|
+
const lineItemChildren = childrenMap[id];
|
|
35
|
+
const childrenLabelId = `cart-line-children-${id}`;
|
|
27
36
|
|
|
28
37
|
return (
|
|
29
38
|
<li key={id} className="cart-line">
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
<div className="cart-line-inner">
|
|
40
|
+
{image && (
|
|
41
|
+
<Image
|
|
42
|
+
alt={title}
|
|
43
|
+
aspectRatio="1/1"
|
|
44
|
+
data={image}
|
|
45
|
+
height={100}
|
|
46
|
+
loading="lazy"
|
|
47
|
+
width={100}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
<div>
|
|
52
|
+
<Link
|
|
53
|
+
prefetch="intent"
|
|
54
|
+
to={lineItemUrl}
|
|
55
|
+
onClick={() => {
|
|
56
|
+
if (layout === 'aside') {
|
|
57
|
+
close();
|
|
58
|
+
}
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
<p>
|
|
62
|
+
<strong>{product.title}</strong>
|
|
63
|
+
</p>
|
|
64
|
+
</Link>
|
|
65
|
+
<ProductPrice price={line?.cost?.totalAmount} />
|
|
66
|
+
<ul>
|
|
67
|
+
{selectedOptions.map((option) => (
|
|
68
|
+
<li key={option.name}>
|
|
69
|
+
<small>
|
|
70
|
+
{option.name}: {option.value}
|
|
71
|
+
</small>
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
|
+
<CartLineQuantity line={line} />
|
|
76
|
+
</div>
|
|
66
77
|
</div>
|
|
78
|
+
|
|
79
|
+
{lineItemChildren ? (
|
|
80
|
+
<div>
|
|
81
|
+
<p id={childrenLabelId} className="sr-only">
|
|
82
|
+
Line items with {product.title}
|
|
83
|
+
</p>
|
|
84
|
+
<ul aria-labelledby={childrenLabelId} className="cart-line-children">
|
|
85
|
+
{lineItemChildren.map((childLine) => (
|
|
86
|
+
<CartLineItem
|
|
87
|
+
childrenMap={childrenMap}
|
|
88
|
+
key={childLine.id}
|
|
89
|
+
line={childLine}
|
|
90
|
+
layout={layout}
|
|
91
|
+
/>
|
|
92
|
+
))}
|
|
93
|
+
</ul>
|
|
94
|
+
</div>
|
|
95
|
+
) : null}
|
|
67
96
|
</li>
|
|
68
97
|
);
|
|
69
98
|
}
|
|
@@ -2,7 +2,7 @@ import {useOptimisticCart} from '@shopify/hydrogen';
|
|
|
2
2
|
import {Link} from 'react-router';
|
|
3
3
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
4
4
|
import {useAside} from '~/components/Aside';
|
|
5
|
-
import {CartLineItem} from '~/components/CartLineItem';
|
|
5
|
+
import {CartLineItem, type CartLine} from '~/components/CartLineItem';
|
|
6
6
|
import {CartSummary} from './CartSummary';
|
|
7
7
|
|
|
8
8
|
export type CartLayout = 'page' | 'aside';
|
|
@@ -12,6 +12,26 @@ export type CartMainProps = {
|
|
|
12
12
|
layout: CartLayout;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export type LineItemChildrenMap = {[parentId: string]: CartLine[]};
|
|
16
|
+
/** Returns a map of all line items and their children. */
|
|
17
|
+
function getLineItemChildrenMap(lines: CartLine[]): LineItemChildrenMap {
|
|
18
|
+
const children: LineItemChildrenMap = {};
|
|
19
|
+
for (const line of lines) {
|
|
20
|
+
if ('parentRelationship' in line && line.parentRelationship?.parent) {
|
|
21
|
+
const parentId = line.parentRelationship.parent.id;
|
|
22
|
+
if (!children[parentId]) children[parentId] = [];
|
|
23
|
+
children[parentId].push(line);
|
|
24
|
+
}
|
|
25
|
+
if ('lineComponents' in line) {
|
|
26
|
+
const lineChildren = getLineItemChildrenMap(line.lineComponents);
|
|
27
|
+
for (const [parentId, childIds] of Object.entries(lineChildren)) {
|
|
28
|
+
if (!children[parentId]) children[parentId] = [];
|
|
29
|
+
children[parentId].push(...childIds);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return children;
|
|
34
|
+
}
|
|
15
35
|
/**
|
|
16
36
|
* The main cart component that displays the cart items and summary.
|
|
17
37
|
* It is used by both the /cart route and the cart aside dialog.
|
|
@@ -27,21 +47,42 @@ export function CartMain({layout, cart: originalCart}: CartMainProps) {
|
|
|
27
47
|
Boolean(cart?.discountCodes?.filter((code) => code.applicable)?.length);
|
|
28
48
|
const className = `cart-main ${withDiscount ? 'with-discount' : ''}`;
|
|
29
49
|
const cartHasItems = cart?.totalQuantity ? cart.totalQuantity > 0 : false;
|
|
50
|
+
const childrenMap = getLineItemChildrenMap(cart?.lines?.nodes ?? []);
|
|
30
51
|
|
|
31
52
|
return (
|
|
32
|
-
<
|
|
53
|
+
<section
|
|
54
|
+
className={className}
|
|
55
|
+
aria-label={layout === 'page' ? 'Cart page' : 'Cart drawer'}
|
|
56
|
+
>
|
|
33
57
|
<CartEmpty hidden={linesCount} layout={layout} />
|
|
34
58
|
<div className="cart-details">
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
<p id="cart-lines" className="sr-only">
|
|
60
|
+
Line items
|
|
61
|
+
</p>
|
|
62
|
+
<div>
|
|
63
|
+
<ul aria-labelledby="cart-lines">
|
|
64
|
+
{(cart?.lines?.nodes ?? []).map((line) => {
|
|
65
|
+
// we do not render non-parent lines at the root of the cart
|
|
66
|
+
if (
|
|
67
|
+
'parentRelationship' in line &&
|
|
68
|
+
line.parentRelationship?.parent
|
|
69
|
+
) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return (
|
|
73
|
+
<CartLineItem
|
|
74
|
+
key={line.id}
|
|
75
|
+
line={line}
|
|
76
|
+
layout={layout}
|
|
77
|
+
childrenMap={childrenMap}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
})}
|
|
40
81
|
</ul>
|
|
41
82
|
</div>
|
|
42
83
|
{cartHasItems && <CartSummary cart={cart} layout={layout} />}
|
|
43
84
|
</div>
|
|
44
|
-
</
|
|
85
|
+
</section>
|
|
45
86
|
);
|
|
46
87
|
}
|
|
47
88
|
|