@shopify/cli-hydrogen 7.1.2 → 8.0.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.
Files changed (136) hide show
  1. package/dist/commands/hydrogen/build-vite.js +19 -10
  2. package/dist/commands/hydrogen/build.js +10 -2
  3. package/dist/commands/hydrogen/check.js +1 -0
  4. package/dist/commands/hydrogen/codegen.js +1 -0
  5. package/dist/commands/hydrogen/customer-account/push.js +170 -0
  6. package/dist/commands/hydrogen/debug/cpu.js +3 -0
  7. package/dist/commands/hydrogen/deploy.js +121 -36
  8. package/dist/commands/hydrogen/dev-vite.js +128 -59
  9. package/dist/commands/hydrogen/dev.js +108 -51
  10. package/dist/commands/hydrogen/env/list.js +7 -8
  11. package/dist/commands/hydrogen/env/pull.js +17 -1
  12. package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
  13. package/dist/commands/hydrogen/generate/route.js +1 -0
  14. package/dist/commands/hydrogen/init.js +45 -17
  15. package/dist/commands/hydrogen/link.js +20 -4
  16. package/dist/commands/hydrogen/list.js +1 -0
  17. package/dist/commands/hydrogen/login.js +1 -0
  18. package/dist/commands/hydrogen/logout.js +1 -0
  19. package/dist/commands/hydrogen/preview.js +31 -16
  20. package/dist/commands/hydrogen/setup/css.js +8 -1
  21. package/dist/commands/hydrogen/setup/markets.js +1 -0
  22. package/dist/commands/hydrogen/setup/vite.js +244 -138
  23. package/dist/commands/hydrogen/setup.js +21 -22
  24. package/dist/commands/hydrogen/shortcut.js +10 -0
  25. package/dist/commands/hydrogen/unlink.js +1 -0
  26. package/dist/commands/hydrogen/upgrade.js +2 -1
  27. package/dist/generator-templates/assets/vite/package.json +3 -4
  28. package/dist/generator-templates/assets/vite/vite.config.js +10 -2
  29. package/dist/generator-templates/starter/CHANGELOG.md +89 -0
  30. package/dist/generator-templates/starter/README.md +3 -44
  31. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
  32. package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
  33. package/dist/generator-templates/starter/app/root.tsx +2 -5
  34. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
  35. package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
  36. package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
  37. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
  38. package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
  39. package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
  40. package/dist/generator-templates/starter/package.json +14 -9
  41. package/dist/generator-templates/starter/server.ts +2 -1
  42. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
  43. package/dist/generator-templates/starter/vite.config.ts +21 -0
  44. package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
  45. package/dist/lib/check-lockfile.js +12 -18
  46. package/dist/lib/codegen.js +37 -13
  47. package/dist/lib/common.js +50 -0
  48. package/dist/lib/cpu-profiler.js +4 -1
  49. package/dist/lib/dev-shared.js +97 -0
  50. package/dist/lib/environment-variables.js +51 -30
  51. package/dist/lib/file.js +8 -1
  52. package/dist/lib/flags.js +37 -16
  53. package/dist/lib/graphql/admin/customer-application-update.js +29 -0
  54. package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
  55. package/dist/lib/graphql/admin/list-environments.js +1 -0
  56. package/dist/lib/graphql/admin/pull-variables.js +4 -4
  57. package/dist/lib/graphql/admin/test-helper.js +37 -0
  58. package/dist/lib/log.js +86 -13
  59. package/dist/lib/mini-oxygen/common.js +19 -33
  60. package/dist/lib/mini-oxygen/index.js +6 -2
  61. package/dist/lib/mini-oxygen/node.js +43 -31
  62. package/dist/lib/mini-oxygen/workerd.js +72 -165
  63. package/dist/lib/missing-routes.js +1 -1
  64. package/dist/lib/onboarding/common.js +82 -70
  65. package/dist/lib/onboarding/local.js +19 -9
  66. package/dist/lib/onboarding/remote.js +35 -30
  67. package/dist/lib/package-managers.js +24 -0
  68. package/dist/lib/remix-config.js +17 -1
  69. package/dist/lib/request-events.js +6 -1
  70. package/dist/lib/setups/i18n/replacers.js +9 -6
  71. package/dist/lib/setups/routes/generate.js +1 -0
  72. package/dist/lib/shell.js +2 -1
  73. package/dist/lib/shopify-config.js +19 -1
  74. package/dist/lib/template-diff.js +36 -15
  75. package/dist/lib/template-downloader.js +35 -5
  76. package/dist/lib/transpile/morph/typedefs.js +5 -2
  77. package/dist/lib/transpile/project.js +8 -4
  78. package/dist/lib/tunneling.js +44 -0
  79. package/dist/lib/virtual-routes.js +1 -1
  80. package/dist/lib/vite-config.js +39 -9
  81. package/oclif.manifest.json +711 -498
  82. package/package.json +32 -24
  83. package/dist/commands/hydrogen/deploy.test.js +0 -553
  84. package/dist/commands/hydrogen/env/list.test.js +0 -148
  85. package/dist/commands/hydrogen/env/pull.test.js +0 -207
  86. package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
  87. package/dist/commands/hydrogen/generate/route.test.js +0 -43
  88. package/dist/commands/hydrogen/init.test.js +0 -641
  89. package/dist/commands/hydrogen/link.test.js +0 -187
  90. package/dist/commands/hydrogen/list.test.js +0 -111
  91. package/dist/commands/hydrogen/setup.test.js +0 -61
  92. package/dist/commands/hydrogen/shortcut.test.js +0 -30
  93. package/dist/commands/hydrogen/unlink.test.js +0 -36
  94. package/dist/commands/hydrogen/upgrade.test.js +0 -786
  95. package/dist/generator-templates/starter/remix.config.js +0 -24
  96. package/dist/lib/auth.test.js +0 -157
  97. package/dist/lib/check-lockfile.test.js +0 -81
  98. package/dist/lib/check-version.test.js +0 -86
  99. package/dist/lib/environment-variables.test.js +0 -149
  100. package/dist/lib/file.test.js +0 -68
  101. package/dist/lib/flags.test.js +0 -43
  102. package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
  103. package/dist/lib/gid.test.js +0 -15
  104. package/dist/lib/graphql/admin/client.test.js +0 -76
  105. package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
  106. package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
  107. package/dist/lib/graphql/admin/list-environments.test.js +0 -44
  108. package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
  109. package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
  110. package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
  111. package/dist/lib/log.test.js +0 -92
  112. package/dist/lib/mini-oxygen/assets.js +0 -134
  113. package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
  114. package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
  115. package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
  116. package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
  117. package/dist/lib/missing-routes.test.js +0 -45
  118. package/dist/lib/remix-version-check.test.js +0 -39
  119. package/dist/lib/remix-version-interop.test.js +0 -13
  120. package/dist/lib/setups/i18n/domains.test.js +0 -39
  121. package/dist/lib/setups/i18n/replacers.test.js +0 -261
  122. package/dist/lib/setups/i18n/subdomains.test.js +0 -39
  123. package/dist/lib/setups/i18n/subfolders.test.js +0 -39
  124. package/dist/lib/setups/routes/generate.test.js +0 -296
  125. package/dist/lib/shell.test.js +0 -111
  126. package/dist/lib/shopify-config.test.js +0 -199
  127. package/dist/lib/string.test.js +0 -16
  128. package/dist/lib/virtual-routes.test.js +0 -49
  129. package/dist/lib/vite/hydrogen-middleware.js +0 -82
  130. package/dist/lib/vite/mini-oxygen.js +0 -152
  131. package/dist/lib/vite/plugins.d.ts +0 -27
  132. package/dist/lib/vite/plugins.js +0 -139
  133. package/dist/lib/vite/shared.js +0 -10
  134. package/dist/lib/vite/utils.js +0 -55
  135. package/dist/lib/vite/worker-entry.js +0 -1518
  136. /package/dist/generator-templates/starter/{.eslintrc.js → .eslintrc.cjs} +0 -0
@@ -1,5 +1,94 @@
1
1
  # skeleton
2
2
 
3
+ ## 1.0.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Update internal libraries for parsing `.env` files. ([#1946](https://github.com/Shopify/hydrogen/pull/1946)) by [@aswamy](https://github.com/aswamy)
8
+
9
+ Please update the `@shopify/cli` dependency in your app to avoid duplicated subdependencies:
10
+
11
+ ```diff
12
+ "dependencies": {
13
+ - "@shopify/cli": "3.56.3",
14
+ + "@shopify/cli": "3.58.0",
15
+ }
16
+ ```
17
+
18
+ - Add Adds magic Catalog route ([#1967](https://github.com/Shopify/hydrogen/pull/1967)) by [@juanpprieto](https://github.com/juanpprieto)
19
+
20
+ - Update Vite plugin imports, and how their options are passed to Remix: ([#1935](https://github.com/Shopify/hydrogen/pull/1935)) by [@frandiox](https://github.com/frandiox)
21
+
22
+ ```diff
23
+ -import {hydrogen, oxygen} from '@shopify/cli-hydrogen/experimental-vite';
24
+ +import {hydrogen} from '@shopify/hydrogen/vite';
25
+ +import {oxygen} from '@shopify/mini-oxygen/vite';
26
+ import {vitePlugin as remix} from '@remix-run/dev';
27
+
28
+ export default defineConfig({
29
+ hydrogen(),
30
+ oxygen(),
31
+ remix({
32
+ - buildDirectory: 'dist',
33
+ + presets: [hydrogen.preset()],
34
+ future: {
35
+ ```
36
+
37
+ - Add `@shopify/mini-oxygen` as a dev dependency for local development: ([#1891](https://github.com/Shopify/hydrogen/pull/1891)) by [@frandiox](https://github.com/frandiox)
38
+
39
+ ```diff
40
+ "devDependencies": {
41
+ "@remix-run/dev": "^2.8.0",
42
+ "@remix-run/eslint-config": "^2.8.0",
43
+ + "@shopify/mini-oxygen": "^3.0.0",
44
+ "@shopify/oxygen-workers-types": "^4.0.0",
45
+ ...
46
+ },
47
+ ```
48
+
49
+ - Add the `customer-account push` command to the Hydrogen CLI. This allows you to push the current `--dev-origin` URL to the Shopify admin to enable secure connection to the Customer Account API for local development. ([#1804](https://github.com/Shopify/hydrogen/pull/1804)) by [@michenly](https://github.com/michenly)
50
+
51
+ - Fix types returned by the `session` object. ([#1869](https://github.com/Shopify/hydrogen/pull/1869)) by [@frandiox](https://github.com/frandiox)
52
+
53
+ In `remix.env.d.ts` or `env.d.ts`, add the following types:
54
+
55
+ ```diff
56
+ import type {
57
+ // ...
58
+ HydrogenCart,
59
+ + HydrogenSessionData,
60
+ } from '@shopify/hydrogen';
61
+
62
+ // ...
63
+
64
+ declare module '@shopify/remix-oxygen' {
65
+ // ...
66
+
67
+ + interface SessionData extends HydrogenSessionData {}
68
+ }
69
+ ```
70
+
71
+ - Codegen dependencies must be now listed explicitly in `package.json`: ([#1962](https://github.com/Shopify/hydrogen/pull/1962)) by [@frandiox](https://github.com/frandiox)
72
+
73
+ ```diff
74
+ {
75
+ "devDependencies": {
76
+ + "@graphql-codegen/cli": "5.0.2",
77
+ "@remix-run/dev": "^2.8.0",
78
+ "@remix-run/eslint-config": "^2.8.0",
79
+ + "@shopify/hydrogen-codegen": "^0.3.0",
80
+ "@shopify/mini-oxygen": "^2.2.5",
81
+ "@shopify/oxygen-workers-types": "^4.0.0",
82
+ ...
83
+ }
84
+ }
85
+ ```
86
+
87
+ - Updated dependencies [[`4eaec272`](https://github.com/Shopify/hydrogen/commit/4eaec272696f1a718aa7cab1070a54385ebc3686), [`14bb5df1`](https://github.com/Shopify/hydrogen/commit/14bb5df1c1513a7991183d34e72220cb2b139cf5), [`646b78d4`](https://github.com/Shopify/hydrogen/commit/646b78d4bc26310121b16000ed4d1c5d5e63957d), [`87072950`](https://github.com/Shopify/hydrogen/commit/870729505f7eb1f1c709799dd036ad02fd94be95), [`5f1295fe`](https://github.com/Shopify/hydrogen/commit/5f1295fe60b86396f364fefef339248a444c988a), [`3c8a7313`](https://github.com/Shopify/hydrogen/commit/3c8a7313cafb0ca21bbca19ac0b3f8ef4ab12655), [`ca1dcbb7`](https://github.com/Shopify/hydrogen/commit/ca1dcbb7d69c458006e25892c86c4478d394a428), [`11879b17`](https://github.com/Shopify/hydrogen/commit/11879b175d78e3326de090a56a044d1e55d0bae8), [`f4d6e5b0`](https://github.com/Shopify/hydrogen/commit/f4d6e5b0244392a7c13b9fa51c5046fd103c3e4f), [`788d86b3`](https://github.com/Shopify/hydrogen/commit/788d86b3a737bff53b4ec3aa9667458b2d45ade7), [`ebaf5529`](https://github.com/Shopify/hydrogen/commit/ebaf5529287b24a70b3146444b18f95b64f9f336), [`da95bb1c`](https://github.com/Shopify/hydrogen/commit/da95bb1c8c644f450053ce649b40dc380e7375dc), [`5bb43304`](https://github.com/Shopify/hydrogen/commit/5bb43304c08427786cfd4f2529e59bd38f593252), [`140e4768`](https://github.com/Shopify/hydrogen/commit/140e4768c880aaed4ba95b1d4c707df6963e011c), [`062d6be7`](https://github.com/Shopify/hydrogen/commit/062d6be7e031c388498ec3d359de51a4bfdfdfd8), [`b3323e59`](https://github.com/Shopify/hydrogen/commit/b3323e59a4381647f1df797c5dc54793f6e0a29a), [`ab0df5a5`](https://github.com/Shopify/hydrogen/commit/ab0df5a52bc587515880ae26f4edd18ba2be83cd), [`ebaf5529`](https://github.com/Shopify/hydrogen/commit/ebaf5529287b24a70b3146444b18f95b64f9f336), [`ebaf5529`](https://github.com/Shopify/hydrogen/commit/ebaf5529287b24a70b3146444b18f95b64f9f336), [`9e899218`](https://github.com/Shopify/hydrogen/commit/9e8992181ce7d27548d35f98b5a4f78b80795ce8), [`a209019f`](https://github.com/Shopify/hydrogen/commit/a209019f722ece4b65f8d5f37c8018c949956b1e), [`d007b7bc`](https://github.com/Shopify/hydrogen/commit/d007b7bc6f6c36e984d937108230ecc7c202fa42), [`a5511cd7`](https://github.com/Shopify/hydrogen/commit/a5511cd7bf9b0f0c4ef0e52cd72418f78c04785b), [`4afedb4d`](https://github.com/Shopify/hydrogen/commit/4afedb4d7202715df9a153e877e8eb281cc3e928), [`34fbae23`](https://github.com/Shopify/hydrogen/commit/34fbae23999eefbd1af1dff44816a52813d75b44), [`e3baaba5`](https://github.com/Shopify/hydrogen/commit/e3baaba54c701a48923ab3fe8078278f2db2c53f), [`99d72f7a`](https://github.com/Shopify/hydrogen/commit/99d72f7afc354abb66ed0e4ffb020bede2781286), [`9351f9f5`](https://github.com/Shopify/hydrogen/commit/9351f9f564267124bcbf986f5550a542c4bf1e30)]:
88
+ - @shopify/cli-hydrogen@8.0.0
89
+ - @shopify/hydrogen@2024.4.0
90
+ - @shopify/remix-oxygen@2.0.4
91
+
3
92
  ## 1.0.6
4
93
 
5
94
  ### Patch Changes
@@ -10,6 +10,7 @@ Hydrogen is Shopify’s stack for headless commerce. Hydrogen is designed to dov
10
10
  - Remix
11
11
  - Hydrogen
12
12
  - Oxygen
13
+ - Vite
13
14
  - Shopify CLI
14
15
  - ESLint
15
16
  - Prettier
@@ -21,7 +22,7 @@ Hydrogen is Shopify’s stack for headless commerce. Hydrogen is designed to dov
21
22
 
22
23
  **Requirements:**
23
24
 
24
- - Node.js version 16.14.0 or higher
25
+ - Node.js version 18.0.0 or higher
25
26
 
26
27
  ```bash
27
28
  npm create @shopify/hydrogen@latest
@@ -41,46 +42,4 @@ npm run dev
41
42
 
42
43
  ## Setup for using Customer Account API (`/account` section)
43
44
 
44
- ### Enabled new Customer Account Experience
45
-
46
- 1. Go to your Shopify admin => Settings => Customer accounts => New customer account
47
-
48
- ### Setup public domain using ngrok
49
-
50
- 1. Setup a [ngrok](https://ngrok.com/) account and add a permanent domain (ie. `https://<your-ngrok-domain>.app`).
51
- 1. Install the [ngrok CLI](https://ngrok.com/download) to use in terminal
52
- 1. Start ngrok using `ngrok http --domain=<your-ngrok-domain>.app 3000`
53
-
54
- > [!IMPORTANT]
55
- > To successfully interact with the Customer Account API routes you will need to use the ngrok domain during development instead of localhost
56
- ### Include public domain in Customer Account API settings
57
-
58
- 1. Go to your Shopify admin => `Hydrogen` or `Headless` app/channel => Customer Account API => Application setup
59
- 1. Edit `Callback URI(s)` to include `https://<your-ngrok-domain>.app/account/authorize`
60
- 1. Edit `Javascript origin(s)` to include your public domain `https://<your-ngrok-domain>.app` or keep it blank
61
- 1. Edit `Logout URI` to include your public domain `https://<your-ngrok-domain>.app` or keep it blank
62
-
63
- ### Add the ngrok domain to the CSP policy
64
-
65
- Modify your `/app/entry.server.tsx` to allow the ngrok domain as a connect-src
66
-
67
- ```diff
68
- - const {nonce, header, NonceProvider} = createContentSecurityPolicy()
69
- + const {nonce, header, NonceProvider} = createContentSecurityPolicy({
70
- + connectSrc: [
71
- + 'wss://<your-ngrok-domain>.app:*', // Your ngrok websocket domain
72
- + ],
73
- + });
74
- ```
75
-
76
- ### Prepare Environment variables
77
-
78
- Run [`npx shopify hydrogen link`](https://shopify.dev/docs/custom-storefronts/hydrogen/cli#link) or [`npx shopify hydrogen env pull`](https://shopify.dev/docs/custom-storefronts/hydrogen/cli#env-pull) to link this app to your own test shop.
79
-
80
- Alternately, the values of the required environment variables "PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID" and "PUBLIC_CUSTOMER_ACCOUNT_API_URL" can be found in customer account api settings in the Hydrogen admin channel.
81
-
82
- > [!IMPORTANT]
83
- > Note that `mock.shop` doesn't supply these variables automatically and your own test shop is required for using Customer Account API
84
-
85
- > [!NOTE]
86
- > B2B features such as contextual pricing is not available in SF API with Customer Account API login. If you require this feature, we suggest using the [legacy-customer-account-flow](https://github.com/Shopify/hydrogen/tree/main/examples/legacy-customer-account-flow). This feature should be available in the Customer Account API in the 2024-04 release.
45
+ Follow step 1 and 2 of <https://shopify.dev/docs/custom-storefronts/building-with-the-customer-account-api/hydrogen#step-1-set-up-a-public-domain-for-local-development>
@@ -1,6 +1,7 @@
1
1
  // NOTE: https://shopify.dev/docs/api/customer/latest/objects/Customer
2
2
  export const CUSTOMER_FRAGMENT = `#graphql
3
3
  fragment Customer on Customer {
4
+ id
4
5
  firstName
5
6
  lastName
6
7
  defaultAddress {
@@ -46,6 +46,7 @@ export const CART_QUERY_FRAGMENT = `#graphql
46
46
  handle
47
47
  title
48
48
  id
49
+ vendor
49
50
  }
50
51
  selectedOptions {
51
52
  name
@@ -55,6 +56,7 @@ export const CART_QUERY_FRAGMENT = `#graphql
55
56
  }
56
57
  }
57
58
  fragment CartApiQuery on Cart {
59
+ updatedAt
58
60
  id
59
61
  checkoutUrl
60
62
  totalQuantity
@@ -9,7 +9,6 @@ import {
9
9
  Meta,
10
10
  Outlet,
11
11
  Scripts,
12
- LiveReload,
13
12
  useMatches,
14
13
  useRouteError,
15
14
  useLoaderData,
@@ -18,8 +17,8 @@ import {
18
17
  type ShouldRevalidateFunction,
19
18
  } from '@remix-run/react';
20
19
  import favicon from './assets/favicon.svg';
21
- import resetStyles from './styles/reset.css';
22
- import appStyles from './styles/app.css';
20
+ import resetStyles from './styles/reset.css?url';
21
+ import appStyles from './styles/app.css?url';
23
22
  import {Layout} from '~/components/Layout';
24
23
 
25
24
  /**
@@ -124,7 +123,6 @@ export default function App() {
124
123
  </Layout>
125
124
  <ScrollRestoration nonce={nonce} />
126
125
  <Scripts nonce={nonce} />
127
- <LiveReload nonce={nonce} />
128
126
  </body>
129
127
  </html>
130
128
  );
@@ -166,7 +164,6 @@ export function ErrorBoundary() {
166
164
  </Layout>
167
165
  <ScrollRestoration nonce={nonce} />
168
166
  <Scripts nonce={nonce} />
169
- <LiveReload nonce={nonce} />
170
167
  </body>
171
168
  </html>
172
169
  );
@@ -99,7 +99,7 @@ function OrderItem({order}: {order: OrderItemFragment}) {
99
99
  return (
100
100
  <>
101
101
  <fieldset>
102
- <Link to={`/account/orders/${order.id}`}>
102
+ <Link to={`/account/orders/${btoa(order.id)}`}>
103
103
  <strong>#{order.number}</strong>
104
104
  </Link>
105
105
  <p>{new Date(order.processedAt).toDateString()}</p>
@@ -1,4 +1,4 @@
1
- import {json, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
1
+ import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
2
2
  import {Form, NavLink, Outlet, useLoaderData} from '@remix-run/react';
3
3
  import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
4
4
 
@@ -0,0 +1,160 @@
1
+ import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
2
+ import {useLoaderData, Link, type MetaFunction} from '@remix-run/react';
3
+ import {
4
+ Pagination,
5
+ getPaginationVariables,
6
+ Image,
7
+ Money,
8
+ } from '@shopify/hydrogen';
9
+ import type {ProductItemFragment} from 'storefrontapi.generated';
10
+ import {useVariantUrl} from '~/lib/variants';
11
+
12
+ export const meta: MetaFunction<typeof loader> = () => {
13
+ return [{title: `Hydrogen | Procuts`}];
14
+ };
15
+
16
+ export async function loader({request, context}: LoaderFunctionArgs) {
17
+ const {storefront} = context;
18
+ const paginationVariables = getPaginationVariables(request, {
19
+ pageBy: 8,
20
+ });
21
+
22
+ const {products} = await storefront.query(CATALOG_QUERY, {
23
+ variables: {...paginationVariables},
24
+ });
25
+
26
+ return json({products});
27
+ }
28
+
29
+ export default function Collection() {
30
+ const {products} = useLoaderData<typeof loader>();
31
+
32
+ return (
33
+ <div className="collection">
34
+ <h1>Products</h1>
35
+ <Pagination connection={products}>
36
+ {({nodes, isLoading, PreviousLink, NextLink}) => (
37
+ <>
38
+ <PreviousLink>
39
+ {isLoading ? 'Loading...' : <span>↑ Load previous</span>}
40
+ </PreviousLink>
41
+ <ProductsGrid products={nodes} />
42
+ <br />
43
+ <NextLink>
44
+ {isLoading ? 'Loading...' : <span>Load more ↓</span>}
45
+ </NextLink>
46
+ </>
47
+ )}
48
+ </Pagination>
49
+ </div>
50
+ );
51
+ }
52
+
53
+ function ProductsGrid({products}: {products: ProductItemFragment[]}) {
54
+ return (
55
+ <div className="products-grid">
56
+ {products.map((product, index) => {
57
+ return (
58
+ <ProductItem
59
+ key={product.id}
60
+ product={product}
61
+ loading={index < 8 ? 'eager' : undefined}
62
+ />
63
+ );
64
+ })}
65
+ </div>
66
+ );
67
+ }
68
+
69
+ function ProductItem({
70
+ product,
71
+ loading,
72
+ }: {
73
+ product: ProductItemFragment;
74
+ loading?: 'eager' | 'lazy';
75
+ }) {
76
+ const variant = product.variants.nodes[0];
77
+ const variantUrl = useVariantUrl(product.handle, variant.selectedOptions);
78
+ return (
79
+ <Link
80
+ className="product-item"
81
+ key={product.id}
82
+ prefetch="intent"
83
+ to={variantUrl}
84
+ >
85
+ {product.featuredImage && (
86
+ <Image
87
+ alt={product.featuredImage.altText || product.title}
88
+ aspectRatio="1/1"
89
+ data={product.featuredImage}
90
+ loading={loading}
91
+ sizes="(min-width: 45em) 400px, 100vw"
92
+ />
93
+ )}
94
+ <h4>{product.title}</h4>
95
+ <small>
96
+ <Money data={product.priceRange.minVariantPrice} />
97
+ </small>
98
+ </Link>
99
+ );
100
+ }
101
+
102
+ const PRODUCT_ITEM_FRAGMENT = `#graphql
103
+ fragment MoneyProductItem on MoneyV2 {
104
+ amount
105
+ currencyCode
106
+ }
107
+ fragment ProductItem on Product {
108
+ id
109
+ handle
110
+ title
111
+ featuredImage {
112
+ id
113
+ altText
114
+ url
115
+ width
116
+ height
117
+ }
118
+ priceRange {
119
+ minVariantPrice {
120
+ ...MoneyProductItem
121
+ }
122
+ maxVariantPrice {
123
+ ...MoneyProductItem
124
+ }
125
+ }
126
+ variants(first: 1) {
127
+ nodes {
128
+ selectedOptions {
129
+ name
130
+ value
131
+ }
132
+ }
133
+ }
134
+ }
135
+ ` as const;
136
+
137
+ // NOTE: https://shopify.dev/docs/api/storefront/2024-01/objects/product
138
+ const CATALOG_QUERY = `#graphql
139
+ query Catalog(
140
+ $country: CountryCode
141
+ $language: LanguageCode
142
+ $first: Int
143
+ $last: Int
144
+ $startCursor: String
145
+ $endCursor: String
146
+ ) @inContext(country: $country, language: $language) {
147
+ products(first: $first, last: $last, before: $startCursor, after: $endCursor) {
148
+ nodes {
149
+ ...ProductItem
150
+ }
151
+ pageInfo {
152
+ hasPreviousPage
153
+ hasNextPage
154
+ startCursor
155
+ endCursor
156
+ }
157
+ }
158
+ }
159
+ ${PRODUCT_ITEM_FRAGMENT}
160
+ ` as const;
@@ -12,7 +12,6 @@ import type {
12
12
  ProductVariantsQuery,
13
13
  ProductVariantFragment,
14
14
  } from 'storefrontapi.generated';
15
-
16
15
  import {
17
16
  Image,
18
17
  Money,
@@ -27,7 +26,7 @@ import type {
27
26
  } from '@shopify/hydrogen/storefront-api-types';
28
27
  import {getVariantUrl} from '~/lib/variants';
29
28
 
30
- export const meta: MetaFunction<typeof loader> = ({data}) => {
29
+ export const meta: MetaFunction<typeof loader> = ({data, location}) => {
31
30
  return [{title: `Hydrogen | ${data?.product.title ?? ''}`}];
32
31
  };
33
32
 
@@ -68,7 +68,7 @@ export type CustomerAddressCreateMutation = {
68
68
 
69
69
  export type CustomerFragment = Pick<
70
70
  CustomerAccountAPI.Customer,
71
- 'firstName' | 'lastName'
71
+ 'id' | 'firstName' | 'lastName'
72
72
  > & {
73
73
  defaultAddress?: CustomerAccountAPI.Maybe<
74
74
  Pick<
@@ -129,7 +129,10 @@ export type CustomerDetailsQueryVariables = CustomerAccountAPI.Exact<{
129
129
  }>;
130
130
 
131
131
  export type CustomerDetailsQuery = {
132
- customer: Pick<CustomerAccountAPI.Customer, 'firstName' | 'lastName'> & {
132
+ customer: Pick<
133
+ CustomerAccountAPI.Customer,
134
+ 'id' | 'firstName' | 'lastName'
135
+ > & {
133
136
  defaultAddress?: CustomerAccountAPI.Maybe<
134
137
  Pick<
135
138
  CustomerAccountAPI.CustomerAddress,
@@ -467,7 +470,7 @@ export type CustomerUpdateMutation = {
467
470
  };
468
471
 
469
472
  interface GeneratedQueryTypes {
470
- '#graphql\n query CustomerDetails {\n customer {\n ...Customer\n }\n }\n #graphql\n fragment Customer on Customer {\n firstName\n lastName\n defaultAddress {\n ...Address\n }\n addresses(first: 6) {\n nodes {\n ...Address\n }\n }\n }\n fragment Address on CustomerAddress {\n id\n formatted\n firstName\n lastName\n company\n address1\n address2\n territoryCode\n zoneCode\n city\n zip\n phoneNumber\n }\n\n': {
473
+ '#graphql\n query CustomerDetails {\n customer {\n ...Customer\n }\n }\n #graphql\n fragment Customer on Customer {\n id\n firstName\n lastName\n defaultAddress {\n ...Address\n }\n addresses(first: 6) {\n nodes {\n ...Address\n }\n }\n }\n fragment Address on CustomerAddress {\n id\n formatted\n firstName\n lastName\n company\n address1\n address2\n territoryCode\n zoneCode\n city\n zip\n phoneNumber\n }\n\n': {
471
474
  return: CustomerDetailsQuery;
472
475
  variables: CustomerDetailsQueryVariables;
473
476
  };
@@ -1,4 +1,4 @@
1
- /// <reference types="@remix-run/dev" />
1
+ /// <reference types="vite/client" />
2
2
  /// <reference types="@shopify/remix-oxygen" />
3
3
  /// <reference types="@shopify/oxygen-workers-types" />
4
4
 
@@ -9,6 +9,7 @@ import type {
9
9
  Storefront,
10
10
  CustomerAccount,
11
11
  HydrogenCart,
12
+ HydrogenSessionData,
12
13
  } from '@shopify/hydrogen';
13
14
  import type {AppSession} from '~/lib/session';
14
15
 
@@ -36,7 +37,7 @@ declare module '@shopify/remix-oxygen' {
36
37
  /**
37
38
  * Declare local additions to the Remix loader context.
38
39
  */
39
- export interface AppLoadContext {
40
+ interface AppLoadContext {
40
41
  env: Env;
41
42
  cart: HydrogenCart;
42
43
  storefront: Storefront;
@@ -44,4 +45,9 @@ declare module '@shopify/remix-oxygen' {
44
45
  session: AppSession;
45
46
  waitUntil: ExecutionContext['waitUntil'];
46
47
  }
48
+
49
+ /**
50
+ * Declare local additions to the Remix session data.
51
+ */
52
+ interface SessionData extends HydrogenSessionData {}
47
53
  }
@@ -2,10 +2,10 @@
2
2
  "name": "skeleton",
3
3
  "private": true,
4
4
  "sideEffects": false,
5
- "version": "1.0.6",
6
- "type": "commonjs",
5
+ "version": "1.0.7",
6
+ "type": "module",
7
7
  "scripts": {
8
- "build": "shopify hydrogen build",
8
+ "build": "shopify hydrogen build --codegen",
9
9
  "dev": "shopify hydrogen dev --codegen",
10
10
  "preview": "npm run build && shopify hydrogen preview",
11
11
  "lint": "eslint --no-error-on-unmatched-pattern --ext .js,.ts,.jsx,.tsx .",
@@ -16,19 +16,22 @@
16
16
  "dependencies": {
17
17
  "@remix-run/react": "^2.8.0",
18
18
  "@remix-run/server-runtime": "^2.8.0",
19
- "@shopify/cli": "3.56.3",
20
- "@shopify/cli-hydrogen": "^7.1.2",
21
- "@shopify/hydrogen": "~2024.1.4",
22
- "@shopify/remix-oxygen": "^2.0.3",
19
+ "@shopify/cli": "3.58.0",
20
+ "@shopify/cli-hydrogen": "^8.0.0",
21
+ "@shopify/hydrogen": "2024.4.0",
22
+ "@shopify/remix-oxygen": "^2.0.4",
23
23
  "graphql": "^16.6.0",
24
24
  "graphql-tag": "^2.12.6",
25
- "isbot": "^3.6.6",
25
+ "isbot": "^3.8.0",
26
26
  "react": "^18.2.0",
27
27
  "react-dom": "^18.2.0"
28
28
  },
29
29
  "devDependencies": {
30
+ "@graphql-codegen/cli": "5.0.2",
30
31
  "@remix-run/dev": "^2.8.0",
31
32
  "@remix-run/eslint-config": "^2.8.0",
33
+ "@shopify/hydrogen-codegen": "^0.3.0",
34
+ "@shopify/mini-oxygen": "^3.0.0",
32
35
  "@shopify/oxygen-workers-types": "^4.0.0",
33
36
  "@shopify/prettier-config": "^1.1.2",
34
37
  "@total-typescript/ts-reset": "^0.4.2",
@@ -38,7 +41,9 @@
38
41
  "eslint": "^8.20.0",
39
42
  "eslint-plugin-hydrogen": "0.12.2",
40
43
  "prettier": "^2.8.4",
41
- "typescript": "^5.2.2"
44
+ "typescript": "^5.2.2",
45
+ "vite": "^5.1.0",
46
+ "vite-tsconfig-paths": "^4.3.1"
42
47
  },
43
48
  "engines": {
44
49
  "node": ">=18.0.0"
@@ -1,5 +1,6 @@
1
+ // @ts-ignore
1
2
  // Virtual entry point for the app
2
- import * as remixBuild from '@remix-run/dev/server-build';
3
+ import * as remixBuild from 'virtual:remix/server-build';
3
4
  import {
4
5
  cartGetIdDefault,
5
6
  cartSetIdDefault,
@@ -31,7 +31,7 @@ export type CartLineFragment = Pick<
31
31
  image?: StorefrontAPI.Maybe<
32
32
  Pick<StorefrontAPI.Image, 'id' | 'url' | 'altText' | 'width' | 'height'>
33
33
  >;
34
- product: Pick<StorefrontAPI.Product, 'handle' | 'title' | 'id'>;
34
+ product: Pick<StorefrontAPI.Product, 'handle' | 'title' | 'id' | 'vendor'>;
35
35
  selectedOptions: Array<
36
36
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
37
37
  >;
@@ -40,7 +40,7 @@ export type CartLineFragment = Pick<
40
40
 
41
41
  export type CartApiQueryFragment = Pick<
42
42
  StorefrontAPI.Cart,
43
- 'id' | 'checkoutUrl' | 'totalQuantity' | 'note'
43
+ 'updatedAt' | 'id' | 'checkoutUrl' | 'totalQuantity' | 'note'
44
44
  > & {
45
45
  buyerIdentity: Pick<
46
46
  StorefrontAPI.CartBuyerIdentity,
@@ -81,7 +81,10 @@ export type CartApiQueryFragment = Pick<
81
81
  'id' | 'url' | 'altText' | 'width' | 'height'
82
82
  >
83
83
  >;
84
- product: Pick<StorefrontAPI.Product, 'handle' | 'title' | 'id'>;
84
+ product: Pick<
85
+ StorefrontAPI.Product,
86
+ 'handle' | 'title' | 'id' | 'vendor'
87
+ >;
85
88
  selectedOptions: Array<
86
89
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
87
90
  >;
@@ -673,6 +676,55 @@ export type StoreCollectionsQuery = {
673
676
  };
674
677
  };
675
678
 
679
+ export type CatalogQueryVariables = StorefrontAPI.Exact<{
680
+ country?: StorefrontAPI.InputMaybe<StorefrontAPI.CountryCode>;
681
+ language?: StorefrontAPI.InputMaybe<StorefrontAPI.LanguageCode>;
682
+ first?: StorefrontAPI.InputMaybe<StorefrontAPI.Scalars['Int']['input']>;
683
+ last?: StorefrontAPI.InputMaybe<StorefrontAPI.Scalars['Int']['input']>;
684
+ startCursor?: StorefrontAPI.InputMaybe<
685
+ StorefrontAPI.Scalars['String']['input']
686
+ >;
687
+ endCursor?: StorefrontAPI.InputMaybe<
688
+ StorefrontAPI.Scalars['String']['input']
689
+ >;
690
+ }>;
691
+
692
+ export type CatalogQuery = {
693
+ products: {
694
+ nodes: Array<
695
+ Pick<StorefrontAPI.Product, 'id' | 'handle' | 'title'> & {
696
+ featuredImage?: StorefrontAPI.Maybe<
697
+ Pick<
698
+ StorefrontAPI.Image,
699
+ 'id' | 'altText' | 'url' | 'width' | 'height'
700
+ >
701
+ >;
702
+ priceRange: {
703
+ minVariantPrice: Pick<
704
+ StorefrontAPI.MoneyV2,
705
+ 'amount' | 'currencyCode'
706
+ >;
707
+ maxVariantPrice: Pick<
708
+ StorefrontAPI.MoneyV2,
709
+ 'amount' | 'currencyCode'
710
+ >;
711
+ };
712
+ variants: {
713
+ nodes: Array<{
714
+ selectedOptions: Array<
715
+ Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
716
+ >;
717
+ }>;
718
+ };
719
+ }
720
+ >;
721
+ pageInfo: Pick<
722
+ StorefrontAPI.PageInfo,
723
+ 'hasPreviousPage' | 'hasNextPage' | 'startCursor' | 'endCursor'
724
+ >;
725
+ };
726
+ };
727
+
676
728
  export type PageQueryVariables = StorefrontAPI.Exact<{
677
729
  language?: StorefrontAPI.InputMaybe<StorefrontAPI.LanguageCode>;
678
730
  country?: StorefrontAPI.InputMaybe<StorefrontAPI.CountryCode>;
@@ -1119,6 +1171,10 @@ interface GeneratedQueryTypes {
1119
1171
  return: StoreCollectionsQuery;
1120
1172
  variables: StoreCollectionsQueryVariables;
1121
1173
  };
1174
+ '#graphql\n query Catalog(\n $country: CountryCode\n $language: LanguageCode\n $first: Int\n $last: Int\n $startCursor: String\n $endCursor: String\n ) @inContext(country: $country, language: $language) {\n products(first: $first, last: $last, before: $startCursor, after: $endCursor) {\n nodes {\n ...ProductItem\n }\n pageInfo {\n hasPreviousPage\n hasNextPage\n startCursor\n endCursor\n }\n }\n }\n #graphql\n fragment MoneyProductItem on MoneyV2 {\n amount\n currencyCode\n }\n fragment ProductItem on Product {\n id\n handle\n title\n featuredImage {\n id\n altText\n url\n width\n height\n }\n priceRange {\n minVariantPrice {\n ...MoneyProductItem\n }\n maxVariantPrice {\n ...MoneyProductItem\n }\n }\n variants(first: 1) {\n nodes {\n selectedOptions {\n name\n value\n }\n }\n }\n }\n\n': {
1175
+ return: CatalogQuery;
1176
+ variables: CatalogQueryVariables;
1177
+ };
1122
1178
  '#graphql\n query Page(\n $language: LanguageCode,\n $country: CountryCode,\n $handle: String!\n )\n @inContext(language: $language, country: $country) {\n page(handle: $handle) {\n id\n title\n body\n seo {\n description\n title\n }\n }\n }\n': {
1123
1179
  return: PageQuery;
1124
1180
  variables: PageQueryVariables;
@@ -0,0 +1,21 @@
1
+ import {defineConfig} from 'vite';
2
+ import {hydrogen} from '@shopify/hydrogen/vite';
3
+ import {oxygen} from '@shopify/mini-oxygen/vite';
4
+ import {vitePlugin as remix} from '@remix-run/dev';
5
+ import tsconfigPaths from 'vite-tsconfig-paths';
6
+
7
+ export default defineConfig({
8
+ plugins: [
9
+ hydrogen(),
10
+ oxygen(),
11
+ remix({
12
+ presets: [hydrogen.preset()],
13
+ future: {
14
+ v3_fetcherPersist: true,
15
+ v3_relativeSplatPath: true,
16
+ v3_throwAbortReason: true,
17
+ },
18
+ }),
19
+ tsconfigPaths(),
20
+ ],
21
+ });