@shopify/cli-hydrogen 3.26.0 → 4.0.0-alpha.1

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 (249) hide show
  1. package/dist/commands/hydrogen/build.js +89 -0
  2. package/dist/commands/hydrogen/dev.js +116 -0
  3. package/dist/commands/hydrogen/init.js +42 -0
  4. package/dist/commands/hydrogen/preview.js +34 -0
  5. package/dist/hooks/init.js +21 -0
  6. package/dist/templates/demo-store/.editorconfig +8 -0
  7. package/dist/templates/demo-store/.eslintignore +4 -0
  8. package/dist/templates/demo-store/.eslintrc.js +16 -0
  9. package/dist/templates/demo-store/.graphqlrc.yml +1 -0
  10. package/dist/templates/demo-store/.prettierignore +2 -0
  11. package/dist/templates/demo-store/.turbo/turbo-build.log +13 -0
  12. package/dist/templates/demo-store/app/components/AccountAddressBook.tsx +97 -0
  13. package/dist/templates/demo-store/app/components/AccountDetails.tsx +41 -0
  14. package/dist/templates/demo-store/app/components/AddToCartButton.tsx +42 -0
  15. package/dist/templates/demo-store/app/components/Breadcrumbs.tsx +36 -0
  16. package/dist/templates/demo-store/app/components/Button.tsx +56 -0
  17. package/dist/templates/demo-store/app/components/Cart.tsx +431 -0
  18. package/dist/templates/demo-store/app/components/CartLoading.tsx +50 -0
  19. package/dist/templates/demo-store/app/components/CountrySelector.tsx +180 -0
  20. package/dist/templates/demo-store/app/components/Drawer.tsx +115 -0
  21. package/dist/templates/demo-store/app/components/FeaturedCollections.tsx +54 -0
  22. package/dist/templates/demo-store/app/components/FeaturedProducts.tsx +116 -0
  23. package/dist/templates/demo-store/app/components/FeaturedSection.tsx +39 -0
  24. package/dist/templates/demo-store/app/components/GenericError.tsx +58 -0
  25. package/dist/templates/demo-store/app/components/Grid.tsx +44 -0
  26. package/dist/templates/demo-store/app/components/Hero.tsx +136 -0
  27. package/dist/templates/demo-store/app/components/Icon.tsx +253 -0
  28. package/dist/templates/demo-store/app/components/Input.tsx +24 -0
  29. package/dist/templates/demo-store/app/components/Layout.tsx +492 -0
  30. package/dist/templates/demo-store/app/components/Link.tsx +46 -0
  31. package/dist/templates/demo-store/app/components/Modal.tsx +46 -0
  32. package/dist/templates/demo-store/app/components/NotFound.tsx +22 -0
  33. package/dist/templates/demo-store/app/components/OrderCard.tsx +85 -0
  34. package/dist/templates/demo-store/app/components/Pagination.tsx +277 -0
  35. package/dist/templates/demo-store/app/components/ProductCard.tsx +146 -0
  36. package/dist/templates/demo-store/app/components/ProductGallery.tsx +114 -0
  37. package/dist/templates/demo-store/app/components/ProductGrid.tsx +93 -0
  38. package/dist/templates/demo-store/app/components/ProductSwimlane.tsx +30 -0
  39. package/dist/templates/demo-store/app/components/Skeleton.tsx +24 -0
  40. package/dist/templates/demo-store/app/components/SortFilter.tsx +411 -0
  41. package/dist/templates/demo-store/app/components/Text.tsx +192 -0
  42. package/dist/templates/demo-store/app/components/index.ts +28 -0
  43. package/dist/templates/demo-store/app/data/countries.ts +194 -0
  44. package/dist/templates/demo-store/app/data/index.ts +1037 -0
  45. package/dist/templates/demo-store/app/entry.client.tsx +4 -0
  46. package/dist/templates/demo-store/app/entry.server.tsx +26 -0
  47. package/dist/templates/demo-store/app/hooks/useCartFetchers.tsx +14 -0
  48. package/dist/templates/demo-store/app/hooks/useIsHydrated.tsx +12 -0
  49. package/dist/templates/demo-store/app/lib/const.ts +10 -0
  50. package/dist/templates/demo-store/app/lib/placeholders.ts +242 -0
  51. package/dist/templates/demo-store/app/lib/seo/common.tsx +324 -0
  52. package/dist/templates/demo-store/app/lib/seo/debugger.tsx +175 -0
  53. package/dist/templates/demo-store/app/lib/seo/image.tsx +32 -0
  54. package/dist/templates/demo-store/app/lib/seo/index.ts +4 -0
  55. package/dist/templates/demo-store/app/lib/seo/seo.tsx +24 -0
  56. package/dist/templates/demo-store/app/lib/seo/types.ts +70 -0
  57. package/dist/templates/demo-store/app/lib/session.server.ts +57 -0
  58. package/dist/templates/demo-store/app/lib/type.ts +21 -0
  59. package/dist/templates/demo-store/app/lib/utils.ts +310 -0
  60. package/dist/templates/demo-store/app/root.tsx +282 -0
  61. package/dist/templates/demo-store/app/routes/$.tsx +7 -0
  62. package/dist/templates/demo-store/app/routes/$lang/$.tsx +1 -0
  63. package/dist/templates/demo-store/app/routes/$lang/[robots.txt].tsx +1 -0
  64. package/dist/templates/demo-store/app/routes/$lang/[sitemap.xml].tsx +1 -0
  65. package/dist/templates/demo-store/app/routes/$lang/account/__private/address/$id.tsx +1 -0
  66. package/dist/templates/demo-store/app/routes/$lang/account/__private/edit.tsx +1 -0
  67. package/dist/templates/demo-store/app/routes/$lang/account/__private/logout.ts +1 -0
  68. package/dist/templates/demo-store/app/routes/$lang/account/__private/orders.$id.tsx +1 -0
  69. package/dist/templates/demo-store/app/routes/$lang/account/__public/activate.$id.$activationToken.tsx +6 -0
  70. package/dist/templates/demo-store/app/routes/$lang/account/__public/login.tsx +7 -0
  71. package/dist/templates/demo-store/app/routes/$lang/account/__public/recover.tsx +1 -0
  72. package/dist/templates/demo-store/app/routes/$lang/account/__public/register.tsx +6 -0
  73. package/dist/templates/demo-store/app/routes/$lang/account/__public/reset.$id.$resetToken.tsx +5 -0
  74. package/dist/templates/demo-store/app/routes/$lang/account.tsx +1 -0
  75. package/dist/templates/demo-store/app/routes/$lang/api/countries.tsx +1 -0
  76. package/dist/templates/demo-store/app/routes/$lang/api/products.tsx +1 -0
  77. package/dist/templates/demo-store/app/routes/$lang/cart.tsx +1 -0
  78. package/dist/templates/demo-store/app/routes/$lang/collections/$collectionHandle.tsx +6 -0
  79. package/dist/templates/demo-store/app/routes/$lang/collections/all.tsx +1 -0
  80. package/dist/templates/demo-store/app/routes/$lang/collections/index.tsx +1 -0
  81. package/dist/templates/demo-store/app/routes/$lang/featured-products.tsx +1 -0
  82. package/dist/templates/demo-store/app/routes/$lang/index.tsx +7 -0
  83. package/dist/templates/demo-store/app/routes/$lang/journal/$journalHandle.tsx +7 -0
  84. package/dist/templates/demo-store/app/routes/$lang/journal/index.tsx +1 -0
  85. package/dist/templates/demo-store/app/routes/$lang/og-image.tsx +1 -0
  86. package/dist/templates/demo-store/app/routes/$lang/pages/$pageHandle.tsx +1 -0
  87. package/dist/templates/demo-store/app/routes/$lang/policies/$policyHandle.tsx +1 -0
  88. package/dist/templates/demo-store/app/routes/$lang/policies/index.tsx +1 -0
  89. package/dist/templates/demo-store/app/routes/$lang/products/$productHandle.tsx +6 -0
  90. package/dist/templates/demo-store/app/routes/$lang/products/index.tsx +1 -0
  91. package/dist/templates/demo-store/app/routes/$lang/search.tsx +6 -0
  92. package/dist/templates/demo-store/app/routes/[robots.txt].tsx +40 -0
  93. package/dist/templates/demo-store/app/routes/[sitemap.xml].tsx +198 -0
  94. package/dist/templates/demo-store/app/routes/account/__private/address/$id.tsx +320 -0
  95. package/dist/templates/demo-store/app/routes/account/__private/edit.tsx +273 -0
  96. package/dist/templates/demo-store/app/routes/account/__private/logout.ts +29 -0
  97. package/dist/templates/demo-store/app/routes/account/__private/orders.$id.tsx +324 -0
  98. package/dist/templates/demo-store/app/routes/account/__public/activate.$id.$activationToken.tsx +218 -0
  99. package/dist/templates/demo-store/app/routes/account/__public/login.tsx +197 -0
  100. package/dist/templates/demo-store/app/routes/account/__public/recover.tsx +144 -0
  101. package/dist/templates/demo-store/app/routes/account/__public/register.tsx +184 -0
  102. package/dist/templates/demo-store/app/routes/account/__public/reset.$id.$resetToken.tsx +214 -0
  103. package/dist/templates/demo-store/app/routes/account.tsx +191 -0
  104. package/dist/templates/demo-store/app/routes/api/countries.tsx +22 -0
  105. package/dist/templates/demo-store/app/routes/api/products.tsx +116 -0
  106. package/dist/templates/demo-store/app/routes/cart.tsx +498 -0
  107. package/dist/templates/demo-store/app/routes/collections/$collectionHandle.tsx +308 -0
  108. package/dist/templates/demo-store/app/routes/collections/all.tsx +5 -0
  109. package/dist/templates/demo-store/app/routes/collections/index.tsx +195 -0
  110. package/dist/templates/demo-store/app/routes/discounts.$code.tsx +60 -0
  111. package/dist/templates/demo-store/app/routes/featured-products.tsx +58 -0
  112. package/dist/templates/demo-store/app/routes/index.tsx +254 -0
  113. package/dist/templates/demo-store/app/routes/journal/$journalHandle.tsx +147 -0
  114. package/dist/templates/demo-store/app/routes/journal/index.tsx +150 -0
  115. package/dist/templates/demo-store/app/routes/og-image.tsx +19 -0
  116. package/dist/templates/demo-store/app/routes/pages/$pageHandle.tsx +82 -0
  117. package/dist/templates/demo-store/app/routes/policies/$policyHandle.tsx +117 -0
  118. package/dist/templates/demo-store/app/routes/policies/index.tsx +104 -0
  119. package/dist/templates/demo-store/app/routes/products/$productHandle.tsx +561 -0
  120. package/dist/templates/demo-store/app/routes/products/index.tsx +155 -0
  121. package/dist/templates/demo-store/app/routes/search.tsx +205 -0
  122. package/dist/templates/demo-store/app/styles/custom-font.css +13 -0
  123. package/dist/templates/demo-store/package-lock.json +25515 -0
  124. package/dist/templates/demo-store/package.json +67 -0
  125. package/dist/templates/demo-store/playwright.config.ts +109 -0
  126. package/dist/templates/demo-store/postcss.config.js +10 -0
  127. package/dist/templates/demo-store/public/favicon.svg +28 -0
  128. package/dist/templates/demo-store/public/fonts/IBMPlexSerif-Text.woff2 +0 -0
  129. package/dist/templates/demo-store/public/fonts/IBMPlexSerif-TextItalic.woff2 +0 -0
  130. package/dist/templates/demo-store/remix.config.js +12 -0
  131. package/dist/templates/demo-store/remix.env.d.ts +34 -0
  132. package/dist/templates/demo-store/remix.init/index.ts +15 -0
  133. package/dist/templates/demo-store/remix.init/package.json +7 -0
  134. package/dist/templates/demo-store/server.ts +87 -0
  135. package/dist/templates/demo-store/styles/app.css +182 -0
  136. package/dist/templates/demo-store/tailwind.config.js +70 -0
  137. package/dist/templates/demo-store/tests/cart.test.ts +70 -0
  138. package/dist/templates/demo-store/tests/seo.test.ts +36 -0
  139. package/dist/templates/demo-store/tests/utils.ts +100 -0
  140. package/dist/templates/demo-store/tsconfig.json +26 -0
  141. package/dist/templates/hello-world/.eslintignore +4 -0
  142. package/dist/templates/hello-world/.eslintrc.js +6 -0
  143. package/dist/templates/hello-world/.graphqlrc.yml +1 -0
  144. package/dist/templates/hello-world/.turbo/turbo-build.log +9 -0
  145. package/dist/templates/hello-world/README.md +20 -0
  146. package/dist/templates/hello-world/app/components/Layout.tsx +15 -0
  147. package/dist/templates/hello-world/app/components/index.ts +1 -0
  148. package/dist/templates/hello-world/app/entry.client.tsx +4 -0
  149. package/dist/templates/hello-world/app/entry.server.tsx +21 -0
  150. package/dist/templates/hello-world/app/root.tsx +212 -0
  151. package/dist/templates/hello-world/app/routes/index.tsx +7 -0
  152. package/dist/templates/hello-world/app/styles/app.css +38 -0
  153. package/dist/templates/hello-world/package-lock.json +27641 -0
  154. package/dist/templates/hello-world/package.json +41 -0
  155. package/dist/templates/hello-world/public/favicon.svg +28 -0
  156. package/dist/templates/hello-world/remix.env.d.ts +29 -0
  157. package/dist/templates/hello-world/server.ts +127 -0
  158. package/dist/templates/hello-world/tsconfig.json +25 -0
  159. package/dist/utils/config.js +81 -0
  160. package/dist/utils/flags.js +15 -0
  161. package/dist/utils/log.js +20 -0
  162. package/dist/utils/mini-oxygen.js +70 -0
  163. package/package.json +27 -64
  164. package/tmp-create-app.mjs +29 -0
  165. package/LICENSE +0 -8
  166. package/README.md +0 -61
  167. package/dist/cli/commands/hydrogen/add/eslint.d.ts +0 -11
  168. package/dist/cli/commands/hydrogen/add/eslint.js +0 -26
  169. package/dist/cli/commands/hydrogen/add/eslint.js.map +0 -1
  170. package/dist/cli/commands/hydrogen/add/tailwind.d.ts +0 -11
  171. package/dist/cli/commands/hydrogen/add/tailwind.js +0 -26
  172. package/dist/cli/commands/hydrogen/add/tailwind.js.map +0 -1
  173. package/dist/cli/commands/hydrogen/build.d.ts +0 -14
  174. package/dist/cli/commands/hydrogen/build.js +0 -49
  175. package/dist/cli/commands/hydrogen/build.js.map +0 -1
  176. package/dist/cli/commands/hydrogen/deploy.d.ts +0 -19
  177. package/dist/cli/commands/hydrogen/deploy.js +0 -58
  178. package/dist/cli/commands/hydrogen/deploy.js.map +0 -1
  179. package/dist/cli/commands/hydrogen/dev.d.ts +0 -13
  180. package/dist/cli/commands/hydrogen/dev.js +0 -31
  181. package/dist/cli/commands/hydrogen/dev.js.map +0 -1
  182. package/dist/cli/commands/hydrogen/info.d.ts +0 -12
  183. package/dist/cli/commands/hydrogen/info.js +0 -28
  184. package/dist/cli/commands/hydrogen/info.js.map +0 -1
  185. package/dist/cli/commands/hydrogen/preview.d.ts +0 -13
  186. package/dist/cli/commands/hydrogen/preview.js +0 -46
  187. package/dist/cli/commands/hydrogen/preview.js.map +0 -1
  188. package/dist/cli/constants.d.ts +0 -15
  189. package/dist/cli/constants.js +0 -16
  190. package/dist/cli/constants.js.map +0 -1
  191. package/dist/cli/flags.d.ts +0 -4
  192. package/dist/cli/flags.js +0 -16
  193. package/dist/cli/flags.js.map +0 -1
  194. package/dist/cli/models/hydrogen.d.ts +0 -22
  195. package/dist/cli/models/hydrogen.js +0 -82
  196. package/dist/cli/models/hydrogen.js.map +0 -1
  197. package/dist/cli/prompts/git-init.d.ts +0 -1
  198. package/dist/cli/prompts/git-init.js +0 -16
  199. package/dist/cli/prompts/git-init.js.map +0 -1
  200. package/dist/cli/services/build/check-lockfile.d.ts +0 -3
  201. package/dist/cli/services/build/check-lockfile.js +0 -80
  202. package/dist/cli/services/build/check-lockfile.js.map +0 -1
  203. package/dist/cli/services/build.d.ts +0 -14
  204. package/dist/cli/services/build.js +0 -44
  205. package/dist/cli/services/build.js.map +0 -1
  206. package/dist/cli/services/deploy/config.d.ts +0 -4
  207. package/dist/cli/services/deploy/config.js +0 -49
  208. package/dist/cli/services/deploy/config.js.map +0 -1
  209. package/dist/cli/services/deploy/error.d.ts +0 -4
  210. package/dist/cli/services/deploy/error.js +0 -11
  211. package/dist/cli/services/deploy/error.js.map +0 -1
  212. package/dist/cli/services/deploy/graphql/create_deployment.d.ts +0 -10
  213. package/dist/cli/services/deploy/graphql/create_deployment.js +0 -15
  214. package/dist/cli/services/deploy/graphql/create_deployment.js.map +0 -1
  215. package/dist/cli/services/deploy/graphql/upload_deployment.d.ts +0 -1
  216. package/dist/cli/services/deploy/graphql/upload_deployment.js +0 -16
  217. package/dist/cli/services/deploy/graphql/upload_deployment.js.map +0 -1
  218. package/dist/cli/services/deploy/types.d.ts +0 -37
  219. package/dist/cli/services/deploy/types.js +0 -2
  220. package/dist/cli/services/deploy/types.js.map +0 -1
  221. package/dist/cli/services/deploy/upload.d.ts +0 -5
  222. package/dist/cli/services/deploy/upload.js +0 -81
  223. package/dist/cli/services/deploy/upload.js.map +0 -1
  224. package/dist/cli/services/deploy.d.ts +0 -2
  225. package/dist/cli/services/deploy.js +0 -103
  226. package/dist/cli/services/deploy.js.map +0 -1
  227. package/dist/cli/services/dev/check-version.d.ts +0 -1
  228. package/dist/cli/services/dev/check-version.js +0 -30
  229. package/dist/cli/services/dev/check-version.js.map +0 -1
  230. package/dist/cli/services/dev.d.ts +0 -10
  231. package/dist/cli/services/dev.js +0 -36
  232. package/dist/cli/services/dev.js.map +0 -1
  233. package/dist/cli/services/eslint.d.ts +0 -8
  234. package/dist/cli/services/eslint.js +0 -74
  235. package/dist/cli/services/eslint.js.map +0 -1
  236. package/dist/cli/services/info.d.ts +0 -7
  237. package/dist/cli/services/info.js +0 -131
  238. package/dist/cli/services/info.js.map +0 -1
  239. package/dist/cli/services/preview.d.ts +0 -12
  240. package/dist/cli/services/preview.js +0 -63
  241. package/dist/cli/services/preview.js.map +0 -1
  242. package/dist/cli/services/tailwind.d.ts +0 -9
  243. package/dist/cli/services/tailwind.js +0 -103
  244. package/dist/cli/services/tailwind.js.map +0 -1
  245. package/dist/cli/utilities/load-config.d.ts +0 -5
  246. package/dist/cli/utilities/load-config.js +0 -6
  247. package/dist/cli/utilities/load-config.js.map +0 -1
  248. package/dist/tsconfig.tsbuildinfo +0 -1
  249. package/oclif.manifest.json +0 -1
@@ -0,0 +1,89 @@
1
+ import path from 'path';
2
+ import * as remix from '@remix-run/dev/dist/compiler.js';
3
+ import fsExtra from 'fs-extra';
4
+ import { output } from '@shopify/cli-kit';
5
+ import colors from '@shopify/cli-kit/node/colors';
6
+ import { getProjectPaths, getRemixConfig } from '../../utils/config.js';
7
+ import { flags } from '../../utils/flags.js';
8
+ import Command from '@shopify/cli-kit/node/base-command';
9
+ import { Flags } from '@oclif/core';
10
+
11
+ const LOG_WORKER_BUILT = "\u{1F4E6} Worker built";
12
+ class Build extends Command {
13
+ static description = "Builds a Hydrogen storefront for production";
14
+ static flags = {
15
+ ...flags,
16
+ sourcemap: Flags.boolean({
17
+ env: "SHOPIFY_HYDROGEN_FLAG_SOURCEMAP"
18
+ }),
19
+ entry: Flags.string({
20
+ env: "SHOPIFY_HYDROGEN_FLAG_SOURCEMAP",
21
+ required: true
22
+ }),
23
+ minify: Flags.boolean({
24
+ description: "Minify the build output",
25
+ env: "SHOPIFY_HYDROGEN_FLAG_MINIFY"
26
+ })
27
+ };
28
+ async run() {
29
+ const { flags: flags2 } = await this.parse(Build);
30
+ const directory = flags2.path ? path.resolve(flags2.path) : process.cwd();
31
+ await runBuild({ ...flags2, path: directory });
32
+ }
33
+ }
34
+ async function runBuild({
35
+ entry,
36
+ sourcemap = true,
37
+ path: appPath
38
+ }) {
39
+ if (!process.env.NODE_ENV) {
40
+ process.env.NODE_ENV = "production";
41
+ }
42
+ const {
43
+ root,
44
+ entryFile,
45
+ buildPath,
46
+ buildPathClient,
47
+ buildPathWorkerFile,
48
+ publicPath
49
+ } = getProjectPaths(appPath, entry);
50
+ console.time(LOG_WORKER_BUILT);
51
+ const remixConfig = await getRemixConfig(root, entryFile, publicPath);
52
+ await fsExtra.rm(buildPath, { force: true, recursive: true });
53
+ output.info(`
54
+ \u{1F3D7}\uFE0F Building in ${process.env.NODE_ENV} mode...`);
55
+ await Promise.all([
56
+ copyPublicFiles(publicPath, buildPathClient),
57
+ remix.build(remixConfig, {
58
+ mode: process.env.NODE_ENV,
59
+ sourcemap,
60
+ onBuildFailure: (failure) => {
61
+ remix.formatBuildFailure(failure);
62
+ throw Error();
63
+ }
64
+ })
65
+ ]);
66
+ if (process.env.NODE_ENV !== "development") {
67
+ console.timeEnd(LOG_WORKER_BUILT);
68
+ const { size } = await fsExtra.stat(buildPathWorkerFile);
69
+ const sizeMB = size / (1024 * 1024);
70
+ output.info(
71
+ output.content` ${colors.dim(
72
+ path.relative(root, buildPathWorkerFile)
73
+ )} ${output.token.yellow(sizeMB.toFixed(2))} MB\n`
74
+ );
75
+ if (sizeMB >= 1) {
76
+ output.warn(
77
+ "\u{1F6A8} Worker bundle exceeds 1 MB! This can delay your worker response.\n"
78
+ );
79
+ }
80
+ }
81
+ }
82
+ function copyPublicFiles(publicPath, buildPathClient) {
83
+ return fsExtra.copy(publicPath, buildPathClient, {
84
+ recursive: true,
85
+ overwrite: true
86
+ });
87
+ }
88
+
89
+ export { copyPublicFiles, Build as default, runBuild };
@@ -0,0 +1,116 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ import * as remix from '@remix-run/dev/dist/compiler.js';
4
+ import { output } from '@shopify/cli-kit';
5
+ import { copyPublicFiles } from './build.js';
6
+ import { getProjectPaths, getRemixConfig } from '../../utils/config.js';
7
+ import { muteDevLogs } from '../../utils/log.js';
8
+ import { flags } from '../../utils/flags.js';
9
+ import Command from '@shopify/cli-kit/node/base-command';
10
+ import { Flags } from '@oclif/core';
11
+ import { startMiniOxygen } from '../../utils/mini-oxygen.js';
12
+
13
+ const LOG_INITIAL_BUILD = "\n\u{1F3C1} Initial build";
14
+ const LOG_REBUILDING = "\u{1F9F1} Rebuilding...";
15
+ const LOG_REBUILT = "\u{1F680} Rebuilt";
16
+ class Dev extends Command {
17
+ static description = "Runs Hydrogen storefront in a MiniOxygen worker in development";
18
+ static flags = {
19
+ ...flags,
20
+ port: Flags.integer({
21
+ description: "Port to run the preview server on",
22
+ env: "SHOPIFY_HYDROGEN_FLAG_PORT",
23
+ default: 3e3
24
+ }),
25
+ entry: Flags.string({
26
+ env: "SHOPIFY_HYDROGEN_FLAG_ENTRY",
27
+ required: true
28
+ })
29
+ };
30
+ async run() {
31
+ const { flags: flags2 } = await this.parse(Dev);
32
+ const directory = flags2.path ? path.resolve(flags2.path) : process.cwd();
33
+ await runDev({ ...flags2, path: directory });
34
+ }
35
+ }
36
+ async function runDev({
37
+ entry,
38
+ port,
39
+ path: appPath
40
+ }) {
41
+ if (!process.env.NODE_ENV)
42
+ process.env.NODE_ENV = "development";
43
+ muteDevLogs();
44
+ await compileAndWatch(getProjectPaths(appPath, entry), { port });
45
+ }
46
+ async function compileAndWatch(projectPaths, options = {}, isInit = true) {
47
+ isInit && console.time(LOG_INITIAL_BUILD);
48
+ const { root, entryFile, publicPath, buildPathClient, buildPathWorkerFile } = projectPaths;
49
+ const shouldReloadRemixApp = (file) => file.startsWith(path.resolve(root, "remix.config.")) || process.env.LOCAL_DEV && (file.includes(path.resolve("/hydrogen/src/templates/")) || file.includes(path.resolve("/hydrogen/dist/build/index.js")));
50
+ const remixConfig = await getRemixConfig(
51
+ root,
52
+ entryFile,
53
+ publicPath,
54
+ options.cacheBust
55
+ );
56
+ const copyingFiles = copyPublicFiles(publicPath, buildPathClient);
57
+ const stopCompileWatcher = await remix.watch(remixConfig, {
58
+ mode: process.env.NODE_ENV,
59
+ async onInitialBuild() {
60
+ await copyingFiles;
61
+ if (isInit) {
62
+ console.timeEnd(LOG_INITIAL_BUILD);
63
+ await startMiniOxygen({
64
+ root,
65
+ port: options.port,
66
+ watch: true,
67
+ buildPathWorkerFile,
68
+ buildPathClient
69
+ });
70
+ }
71
+ },
72
+ async onFileCreated(file) {
73
+ output.info(`
74
+ \u{1F4C4} File created: ${path.relative(root, file)}`);
75
+ if (file.startsWith(publicPath)) {
76
+ await copyPublicFiles(file, file.replace(publicPath, buildPathClient));
77
+ }
78
+ if (shouldReloadRemixApp(file)) {
79
+ await reloadRemixApp(file);
80
+ }
81
+ },
82
+ async onFileChanged(file) {
83
+ output.info(`
84
+ \u{1F4C4} File changed: ${path.relative(root, file)}`);
85
+ if (file.startsWith(publicPath)) {
86
+ await copyPublicFiles(file, file.replace(publicPath, buildPathClient));
87
+ }
88
+ if (shouldReloadRemixApp(file)) {
89
+ await reloadRemixApp(file);
90
+ }
91
+ },
92
+ async onFileDeleted(file) {
93
+ output.info(`
94
+ \u{1F4C4} File deleted: ${path.relative(root, file)}`);
95
+ if (file.startsWith(publicPath)) {
96
+ await fs.unlink(file.replace(publicPath, buildPathClient));
97
+ }
98
+ if (shouldReloadRemixApp(file)) {
99
+ await reloadRemixApp(file);
100
+ }
101
+ },
102
+ onRebuildStart() {
103
+ output.info(LOG_REBUILDING);
104
+ console.time(LOG_REBUILT);
105
+ },
106
+ async onRebuildFinish() {
107
+ console.timeEnd(LOG_REBUILT);
108
+ }
109
+ });
110
+ async function reloadRemixApp(cacheBust) {
111
+ await stopCompileWatcher();
112
+ compileAndWatch(projectPaths, { ...options, cacheBust }, false);
113
+ }
114
+ }
115
+
116
+ export { Dev as default, runDev };
@@ -0,0 +1,42 @@
1
+ import { cli } from '@remix-run/dev';
2
+ import Command from '@shopify/cli-kit/node/base-command';
3
+ import { Flags } from '@oclif/core';
4
+
5
+ class Init extends Command {
6
+ static description = "Creates a new Hydrogen storefront project";
7
+ static flags = {
8
+ typescript: Flags.boolean({
9
+ description: "Use TypeScript",
10
+ env: "SHOPIFY_HYDROGEN_FLAG_TYPESCRIPT"
11
+ }),
12
+ template: Flags.string({
13
+ description: "The template to use",
14
+ env: "SHOPIFY_HYDROGEN_FLAG_TEMPLATE",
15
+ default: "../../templates/demo-store",
16
+ required: true
17
+ }),
18
+ token: Flags.string({
19
+ description: "A GitHub token used to access access private repository templates"
20
+ })
21
+ };
22
+ async run() {
23
+ const { flags } = await this.parse(Init);
24
+ await runInit({ ...flags });
25
+ }
26
+ }
27
+ function runInit({
28
+ template,
29
+ typescript,
30
+ token
31
+ }) {
32
+ const defaults = [
33
+ "--template",
34
+ template,
35
+ "--install",
36
+ typescript ? "--typescript" : "",
37
+ token ? `--token ${token}` : ""
38
+ ];
39
+ cli.run(["create", ...defaults]);
40
+ }
41
+
42
+ export { Init as default, runInit };
@@ -0,0 +1,34 @@
1
+ import Command from '@shopify/cli-kit/node/base-command';
2
+ import { muteDevLogs } from '../../utils/log.js';
3
+ import { getProjectPaths } from '../../utils/config.js';
4
+ import { flags } from '../../utils/flags.js';
5
+ import { startMiniOxygen } from '../../utils/mini-oxygen.js';
6
+
7
+ class Preview extends Command {
8
+ static description = "Runs an existing Hydrogen storefront build in a MiniOxygen worker";
9
+ static flags = {
10
+ paths: flags.path,
11
+ port: flags.port
12
+ };
13
+ async run() {
14
+ const { flags: flags2 } = await this.parse(Preview);
15
+ await runPreview({ ...flags2 });
16
+ }
17
+ }
18
+ async function runPreview({
19
+ port,
20
+ path: appPath
21
+ }) {
22
+ if (!process.env.NODE_ENV)
23
+ process.env.NODE_ENV = "production";
24
+ const { root, buildPathWorkerFile, buildPathClient } = getProjectPaths(appPath);
25
+ muteDevLogs({ workerReload: false });
26
+ await startMiniOxygen({
27
+ root,
28
+ port,
29
+ buildPathClient,
30
+ buildPathWorkerFile
31
+ });
32
+ }
33
+
34
+ export { Preview as default, runPreview };
@@ -0,0 +1,21 @@
1
+ import { spawnSync } from 'child_process';
2
+ import { output } from '@shopify/cli-kit';
3
+
4
+ const EXPERIMENTAL_VM_MODULES_FLAG = "--experimental-vm-modules";
5
+ const hook = async function(options) {
6
+ if (!options.id || !["hydrogen:dev", "hydrogen:preview"].includes(options.id)) {
7
+ return;
8
+ }
9
+ if (!process.execArgv.includes(EXPERIMENTAL_VM_MODULES_FLAG) && !(process.env.NODE_OPTIONS ?? "").includes(EXPERIMENTAL_VM_MODULES_FLAG)) {
10
+ output.debug(
11
+ `Restarting CLI process with ${EXPERIMENTAL_VM_MODULES_FLAG} flag.`
12
+ );
13
+ const [command, ...args] = process.argv;
14
+ args.unshift(EXPERIMENTAL_VM_MODULES_FLAG);
15
+ spawnSync(command, args, { stdio: "inherit" });
16
+ process.exit(0);
17
+ }
18
+ };
19
+ var init_default = hook;
20
+
21
+ export { init_default as default };
@@ -0,0 +1,8 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ charset = utf-8
7
+ trim_trailing_whitespace = true
8
+ insert_final_newline = true
@@ -0,0 +1,4 @@
1
+ build
2
+ node_modules
3
+ bin
4
+ *.d.ts
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @type {import("@types/eslint").Linter.BaseConfig}
3
+ */
4
+ module.exports = {
5
+ extends: ['plugin:hydrogen/recommended', 'plugin:hydrogen/typescript'],
6
+ rules: {
7
+ '@typescript-eslint/ban-ts-comment': 'off',
8
+ '@typescript-eslint/naming-convention': 'off',
9
+ 'hydrogen/prefer-image-component': 'off',
10
+ 'no-useless-escape': 'off',
11
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
12
+ 'no-case-declarations': 'off',
13
+ // TODO: Remove jest plugin from hydrogen/eslint-plugin
14
+ 'jest/no-deprecated-functions': 'off',
15
+ },
16
+ };
@@ -0,0 +1 @@
1
+ schema: node_modules/@shopify/hydrogen-react/storefront.schema.json
@@ -0,0 +1,2 @@
1
+ node_modules
2
+ build
@@ -0,0 +1,13 @@
1
+
2
+ > demo-store@0.0.0 build
3
+ > npm run build:css && shopify hydrogen build --entry ./server
4
+
5
+
6
+ > demo-store@0.0.0 build:css
7
+ > postcss styles --base styles --dir app/styles --env production
8
+
9
+
10
+ 🏗️ Building in production mode...
11
+ 📦 Worker built: 1.466s
12
+ dist/worker/index.js 0.57 MB
13
+
@@ -0,0 +1,97 @@
1
+ import {Form} from '@remix-run/react';
2
+ import type {
3
+ Customer,
4
+ MailingAddress,
5
+ } from '@shopify/hydrogen-react/storefront-api-types';
6
+ import {Button, Link, Text} from '~/components';
7
+
8
+ export function AccountAddressBook({
9
+ customer,
10
+ addresses,
11
+ }: {
12
+ customer: Customer;
13
+ addresses: MailingAddress[];
14
+ }) {
15
+ return (
16
+ <>
17
+ <div className="grid w-full gap-4 p-4 py-6 md:gap-8 md:p-8 lg:p-12">
18
+ <h3 className="font-bold text-lead">Address Book</h3>
19
+ <div>
20
+ {!addresses?.length && (
21
+ <Text className="mb-1" width="narrow" as="p" size="copy">
22
+ You haven&apos;t saved any addresses yet.
23
+ </Text>
24
+ )}
25
+ <div className="w-48">
26
+ <Button
27
+ to="address/add"
28
+ className="mt-2 text-sm w-full mb-6"
29
+ variant="secondary"
30
+ >
31
+ Add an Address
32
+ </Button>
33
+ </div>
34
+ {Boolean(addresses?.length) && (
35
+ <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
36
+ {customer.defaultAddress && (
37
+ <Address address={customer.defaultAddress} defaultAddress />
38
+ )}
39
+ {addresses
40
+ .filter((address) => address.id !== customer.defaultAddress?.id)
41
+ .map((address) => (
42
+ <Address key={address.id} address={address} />
43
+ ))}
44
+ </div>
45
+ )}
46
+ </div>
47
+ </div>
48
+ </>
49
+ );
50
+ }
51
+
52
+ function Address({
53
+ address,
54
+ defaultAddress,
55
+ }: {
56
+ address: MailingAddress;
57
+ defaultAddress?: boolean;
58
+ }) {
59
+ return (
60
+ <div className="lg:p-8 p-6 border border-gray-200 rounded flex flex-col">
61
+ {defaultAddress && (
62
+ <div className="mb-3 flex flex-row">
63
+ <span className="px-3 py-1 text-xs font-medium rounded-full bg-primary/20 text-primary/50">
64
+ Default
65
+ </span>
66
+ </div>
67
+ )}
68
+ <ul className="flex-1 flex-row">
69
+ {(address.firstName || address.lastName) && (
70
+ <li>
71
+ {'' +
72
+ (address.firstName && address.firstName + ' ') +
73
+ address?.lastName}
74
+ </li>
75
+ )}
76
+ {address.formatted &&
77
+ address.formatted.map((line: string) => <li key={line}>{line}</li>)}
78
+ </ul>
79
+
80
+ <div className="flex flex-row font-medium mt-6">
81
+ <Link
82
+ to={`/account/address/${encodeURIComponent(address.id)}`}
83
+ className="text-left underline text-sm"
84
+ prefetch="intent"
85
+ >
86
+ Edit
87
+ </Link>
88
+ <Form action="address/delete" method="delete">
89
+ <input type="hidden" name="addressId" value={address.id} />
90
+ <button className="text-left text-primary/50 ml-6 text-sm">
91
+ Remove
92
+ </button>
93
+ </Form>
94
+ </div>
95
+ </div>
96
+ );
97
+ }
@@ -0,0 +1,41 @@
1
+ import type {Customer} from '@shopify/hydrogen-react/storefront-api-types';
2
+ import {Link} from '~/components';
3
+
4
+ export function AccountDetails({customer}: {customer: Customer}) {
5
+ const {firstName, lastName, email, phone} = customer;
6
+
7
+ return (
8
+ <>
9
+ <div className="grid w-full gap-4 p-4 py-6 md:gap-8 md:p-8 lg:p-12">
10
+ <h3 className="font-bold text-lead">Account Details</h3>
11
+ <div className="lg:p-8 p-6 border border-gray-200 rounded">
12
+ <div className="flex">
13
+ <h3 className="font-bold text-base flex-1">Profile & Security</h3>
14
+ <Link
15
+ prefetch="intent"
16
+ className="underline text-sm font-normal"
17
+ to="/account/edit"
18
+ >
19
+ Edit
20
+ </Link>
21
+ </div>
22
+ <div className="mt-4 text-sm text-primary/50">Name</div>
23
+ <p className="mt-1">
24
+ {firstName || lastName
25
+ ? (firstName ? firstName + ' ' : '') + lastName
26
+ : 'Add name'}{' '}
27
+ </p>
28
+
29
+ <div className="mt-4 text-sm text-primary/50">Contact</div>
30
+ <p className="mt-1">{phone ?? 'Add mobile'}</p>
31
+
32
+ <div className="mt-4 text-sm text-primary/50">Email address</div>
33
+ <p className="mt-1">{email}</p>
34
+
35
+ <div className="mt-4 text-sm text-primary/50">Password</div>
36
+ <p className="mt-1">**************</p>
37
+ </div>
38
+ </div>
39
+ </>
40
+ );
41
+ }
@@ -0,0 +1,42 @@
1
+ import type {CartLineInput} from '@shopify/hydrogen-react/storefront-api-types';
2
+ import {useFetcher, useMatches} from '@remix-run/react';
3
+ import {Button} from '~/components';
4
+ import {CartAction} from '~/lib/type';
5
+
6
+ export function AddToCartButton({
7
+ children,
8
+ lines,
9
+ className = '',
10
+ variant = 'primary',
11
+ width = 'full',
12
+ ...props
13
+ }: {
14
+ children: React.ReactNode;
15
+ lines: CartLineInput[];
16
+ className?: string;
17
+ variant?: 'primary' | 'secondary' | 'inline';
18
+ width?: 'auto' | 'full';
19
+ [key: string]: any;
20
+ }) {
21
+ const [root] = useMatches();
22
+ const selectedLocale = root?.data?.selectedLocale;
23
+ const fetcher = useFetcher();
24
+
25
+ return (
26
+ <fetcher.Form action="/cart" method="post">
27
+ <input type="hidden" name="cartAction" value={CartAction.ADD_TO_CART} />
28
+ <input type="hidden" name="countryCode" value={selectedLocale.country} />
29
+ <input type="hidden" name="lines" value={JSON.stringify(lines)} />
30
+ <Button
31
+ as="button"
32
+ type="submit"
33
+ width={width}
34
+ variant={variant}
35
+ className={className}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </Button>
40
+ </fetcher.Form>
41
+ );
42
+ }
@@ -0,0 +1,36 @@
1
+ import {Text} from './Text';
2
+ import {Link} from './Link';
3
+
4
+ interface Breadcrumb {
5
+ handle: string;
6
+ title: string;
7
+ id: string;
8
+ }
9
+
10
+ // Renders a breadcrumb trail from a references metafield list
11
+ export function Breadcrumbs({
12
+ breadcrumbs,
13
+ }: {
14
+ breadcrumbs?: Breadcrumb[] | null;
15
+ }) {
16
+ if (!breadcrumbs || breadcrumbs.length === 0) {
17
+ return null;
18
+ }
19
+
20
+ const breadcrumbsMarkup = breadcrumbs.map((breadcrumb, index) => {
21
+ const isLastBreadcrumb = index === breadcrumbs.length - 1;
22
+
23
+ return isLastBreadcrumb ? (
24
+ <Text key={breadcrumb.id} as="span">
25
+ {breadcrumb.title}
26
+ </Text>
27
+ ) : (
28
+ <span key={breadcrumb.id}>
29
+ <Link to={`/collections/${breadcrumb.handle}`}>{breadcrumb.title}</Link>
30
+ <span className="px-2">/</span>
31
+ </span>
32
+ );
33
+ });
34
+
35
+ return <nav className="flex items-center">{breadcrumbsMarkup}</nav>;
36
+ }
@@ -0,0 +1,56 @@
1
+ import {forwardRef} from 'react';
2
+ import {Link} from '@remix-run/react';
3
+ import clsx from 'clsx';
4
+
5
+ import {missingClass} from '~/lib/utils';
6
+
7
+ export const Button = forwardRef(
8
+ (
9
+ {
10
+ as = 'button',
11
+ className = '',
12
+ variant = 'primary',
13
+ width = 'auto',
14
+ ...props
15
+ }: {
16
+ as?: React.ElementType;
17
+ className?: string;
18
+ variant?: 'primary' | 'secondary' | 'inline';
19
+ width?: 'auto' | 'full';
20
+ [key: string]: any;
21
+ },
22
+ ref,
23
+ ) => {
24
+ const Component = props?.to ? Link : as;
25
+
26
+ const baseButtonClasses =
27
+ 'inline-block rounded font-medium text-center py-3 px-6';
28
+
29
+ const variants = {
30
+ primary: `${baseButtonClasses} bg-primary text-contrast`,
31
+ secondary: `${baseButtonClasses} border border-primary/10 bg-contrast text-primary`,
32
+ inline: 'border-b border-primary/10 leading-none pb-1',
33
+ };
34
+
35
+ const widths = {
36
+ auto: 'w-auto',
37
+ full: 'w-full',
38
+ };
39
+
40
+ const styles = clsx(
41
+ missingClass(className, 'bg-') && variants[variant],
42
+ missingClass(className, 'w-') && widths[width],
43
+ className,
44
+ );
45
+
46
+ return (
47
+ <Component
48
+ // @todo: not supported until react-router makes it into Remix.
49
+ // preventScrollReset={true}
50
+ className={styles}
51
+ {...props}
52
+ ref={ref}
53
+ />
54
+ );
55
+ },
56
+ );