@shopify/cli-hydrogen 5.0.2 → 5.1.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 (243) hide show
  1. package/dist/commands/hydrogen/build.js +16 -2
  2. package/dist/commands/hydrogen/codegen-unstable.js +13 -24
  3. package/dist/commands/hydrogen/dev.js +45 -39
  4. package/dist/commands/hydrogen/env/list.js +25 -24
  5. package/dist/commands/hydrogen/env/list.test.js +46 -43
  6. package/dist/commands/hydrogen/env/pull.js +53 -25
  7. package/dist/commands/hydrogen/env/pull.test.js +123 -42
  8. package/dist/commands/hydrogen/generate/route.js +31 -132
  9. package/dist/commands/hydrogen/generate/route.test.js +34 -126
  10. package/dist/commands/hydrogen/init.js +46 -127
  11. package/dist/commands/hydrogen/init.test.js +352 -100
  12. package/dist/commands/hydrogen/link.js +70 -69
  13. package/dist/commands/hydrogen/link.test.js +72 -107
  14. package/dist/commands/hydrogen/list.js +22 -12
  15. package/dist/commands/hydrogen/list.test.js +51 -48
  16. package/dist/commands/hydrogen/login.js +31 -0
  17. package/dist/commands/hydrogen/logout.js +21 -0
  18. package/dist/commands/hydrogen/setup/css.js +79 -0
  19. package/dist/commands/hydrogen/setup/markets.js +53 -0
  20. package/dist/commands/hydrogen/setup.js +133 -0
  21. package/dist/commands/hydrogen/shortcut.js +2 -45
  22. package/dist/commands/hydrogen/shortcut.test.js +10 -37
  23. package/dist/generator-templates/assets/css-modules/package.json +6 -0
  24. package/dist/generator-templates/assets/postcss/package.json +10 -0
  25. package/dist/generator-templates/assets/postcss/postcss.config.js +8 -0
  26. package/dist/generator-templates/assets/tailwind/package.json +13 -0
  27. package/dist/generator-templates/assets/tailwind/postcss.config.js +10 -0
  28. package/dist/generator-templates/assets/tailwind/tailwind.config.js +8 -0
  29. package/dist/generator-templates/assets/tailwind/tailwind.css +3 -0
  30. package/dist/generator-templates/assets/vanilla-extract/package.json +9 -0
  31. package/dist/generator-templates/starter/.eslintignore +5 -0
  32. package/dist/generator-templates/starter/.eslintrc.js +18 -0
  33. package/dist/generator-templates/starter/.graphqlrc.yml +1 -0
  34. package/dist/generator-templates/starter/README.md +40 -0
  35. package/dist/generator-templates/starter/app/components/Aside.tsx +47 -0
  36. package/dist/generator-templates/starter/app/components/Cart.tsx +340 -0
  37. package/dist/generator-templates/starter/app/components/Footer.tsx +99 -0
  38. package/dist/generator-templates/starter/app/components/Header.tsx +178 -0
  39. package/dist/generator-templates/starter/app/components/Layout.tsx +95 -0
  40. package/dist/generator-templates/starter/app/components/Search.tsx +480 -0
  41. package/dist/generator-templates/starter/app/entry.client.tsx +12 -0
  42. package/dist/generator-templates/starter/app/entry.server.tsx +33 -0
  43. package/dist/generator-templates/starter/app/root.tsx +270 -0
  44. package/dist/generator-templates/starter/app/routes/$.tsx +7 -0
  45. package/dist/generator-templates/{routes → starter/app/routes}/[robots.txt].tsx +47 -69
  46. package/dist/generator-templates/starter/app/routes/[sitemap.xml].tsx +174 -0
  47. package/dist/generator-templates/starter/app/routes/_index.tsx +145 -0
  48. package/dist/generator-templates/starter/app/routes/account.$.tsx +9 -0
  49. package/dist/generator-templates/starter/app/routes/account.addresses.tsx +563 -0
  50. package/dist/generator-templates/starter/app/routes/account.orders.$id.tsx +309 -0
  51. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +196 -0
  52. package/dist/generator-templates/starter/app/routes/account.profile.tsx +289 -0
  53. package/dist/generator-templates/starter/app/routes/account.tsx +203 -0
  54. package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +157 -0
  55. package/dist/generator-templates/starter/app/routes/account_.login.tsx +143 -0
  56. package/dist/generator-templates/starter/app/routes/account_.logout.tsx +33 -0
  57. package/dist/generator-templates/starter/app/routes/account_.recover.tsx +124 -0
  58. package/dist/generator-templates/starter/app/routes/account_.register.tsx +207 -0
  59. package/dist/generator-templates/starter/app/routes/account_.reset.$id.$resetToken.tsx +136 -0
  60. package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +342 -0
  61. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +88 -0
  62. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle._index.tsx +162 -0
  63. package/dist/generator-templates/starter/app/routes/blogs._index.tsx +94 -0
  64. package/dist/generator-templates/starter/app/routes/cart.tsx +104 -0
  65. package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +184 -0
  66. package/dist/generator-templates/starter/app/routes/collections._index.tsx +120 -0
  67. package/dist/generator-templates/starter/app/routes/pages.$handle.tsx +57 -0
  68. package/dist/generator-templates/starter/app/routes/policies.$handle.tsx +94 -0
  69. package/dist/generator-templates/starter/app/routes/policies._index.tsx +63 -0
  70. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +418 -0
  71. package/dist/generator-templates/starter/app/routes/search.tsx +168 -0
  72. package/dist/generator-templates/starter/app/styles/app.css +473 -0
  73. package/dist/generator-templates/starter/app/styles/reset.css +129 -0
  74. package/dist/generator-templates/starter/app/utils.ts +46 -0
  75. package/dist/generator-templates/starter/package.json +43 -0
  76. package/dist/generator-templates/starter/public/favicon.svg +28 -0
  77. package/dist/generator-templates/starter/remix.config.js +26 -0
  78. package/dist/generator-templates/starter/remix.env.d.ts +39 -0
  79. package/dist/generator-templates/starter/server.ts +253 -0
  80. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +1906 -0
  81. package/dist/generator-templates/starter/tsconfig.json +22 -0
  82. package/dist/lib/auth.js +123 -0
  83. package/dist/lib/auth.test.js +157 -0
  84. package/dist/lib/build.js +51 -0
  85. package/dist/lib/check-version.js +3 -3
  86. package/dist/lib/check-version.test.js +24 -0
  87. package/dist/lib/codegen.js +26 -17
  88. package/dist/lib/environment-variables.js +68 -0
  89. package/dist/lib/environment-variables.test.js +147 -0
  90. package/dist/lib/file.js +41 -0
  91. package/dist/lib/file.test.js +69 -0
  92. package/dist/lib/flags.js +39 -2
  93. package/dist/lib/format-code.js +26 -0
  94. package/dist/lib/gid.js +12 -0
  95. package/dist/lib/{graphql.test.js → gid.test.js} +1 -1
  96. package/dist/lib/graphql/admin/client.js +27 -0
  97. package/dist/lib/graphql/admin/client.test.js +51 -0
  98. package/dist/lib/graphql/admin/create-storefront.js +13 -15
  99. package/dist/lib/graphql/admin/create-storefront.test.js +64 -0
  100. package/dist/lib/graphql/admin/fetch-job.js +6 -15
  101. package/dist/lib/graphql/admin/link-storefront.js +7 -11
  102. package/dist/lib/graphql/admin/link-storefront.test.js +38 -0
  103. package/dist/lib/graphql/admin/list-environments.js +2 -2
  104. package/dist/lib/graphql/admin/list-environments.test.js +44 -0
  105. package/dist/lib/graphql/admin/list-storefronts.js +7 -11
  106. package/dist/lib/graphql/admin/list-storefronts.test.js +44 -0
  107. package/dist/lib/graphql/admin/pull-variables.js +3 -3
  108. package/dist/lib/graphql/admin/pull-variables.test.js +37 -0
  109. package/dist/lib/graphql/business-platform/user-account.js +83 -0
  110. package/dist/lib/graphql/business-platform/user-account.test.js +80 -0
  111. package/dist/lib/log.js +185 -9
  112. package/dist/lib/log.test.js +92 -0
  113. package/dist/lib/mini-oxygen.js +19 -9
  114. package/dist/lib/missing-routes.js +0 -2
  115. package/dist/lib/onboarding/common.js +456 -0
  116. package/dist/lib/onboarding/index.js +2 -0
  117. package/dist/lib/onboarding/local.js +229 -0
  118. package/dist/lib/onboarding/remote.js +89 -0
  119. package/dist/lib/remix-version-interop.js +5 -5
  120. package/dist/lib/remix-version-interop.test.js +11 -1
  121. package/dist/lib/render-errors.js +13 -11
  122. package/dist/lib/setups/css/assets.js +89 -0
  123. package/dist/lib/setups/css/css-modules.js +22 -0
  124. package/dist/lib/setups/css/index.js +44 -0
  125. package/dist/lib/setups/css/postcss.js +34 -0
  126. package/dist/lib/setups/css/replacers.js +137 -0
  127. package/dist/lib/setups/css/tailwind.js +54 -0
  128. package/dist/lib/setups/css/vanilla-extract.js +22 -0
  129. package/dist/lib/setups/i18n/domains.test.js +25 -0
  130. package/dist/lib/setups/i18n/index.js +46 -0
  131. package/dist/lib/setups/i18n/replacers.js +227 -0
  132. package/dist/lib/setups/i18n/subdomains.test.js +25 -0
  133. package/dist/lib/setups/i18n/subfolders.test.js +25 -0
  134. package/dist/lib/setups/i18n/templates/domains.js +14 -0
  135. package/dist/lib/setups/i18n/templates/domains.ts +25 -0
  136. package/dist/lib/setups/i18n/templates/subdomains.js +14 -0
  137. package/dist/lib/setups/i18n/templates/subdomains.ts +24 -0
  138. package/dist/lib/setups/i18n/templates/subfolders.js +14 -0
  139. package/dist/lib/setups/i18n/templates/subfolders.ts +28 -0
  140. package/dist/lib/setups/routes/generate.js +244 -0
  141. package/dist/lib/setups/routes/generate.test.js +313 -0
  142. package/dist/lib/shell.js +52 -5
  143. package/dist/lib/shell.test.js +42 -16
  144. package/dist/lib/shopify-config.js +23 -18
  145. package/dist/lib/shopify-config.test.js +63 -73
  146. package/dist/lib/template-downloader.js +9 -7
  147. package/dist/lib/transpile-ts.js +9 -29
  148. package/dist/virtual-routes/routes/index.jsx +40 -19
  149. package/oclif.manifest.json +710 -1
  150. package/package.json +16 -16
  151. package/dist/commands/hydrogen/build.d.ts +0 -23
  152. package/dist/commands/hydrogen/check.d.ts +0 -15
  153. package/dist/commands/hydrogen/codegen-unstable.d.ts +0 -15
  154. package/dist/commands/hydrogen/dev.d.ts +0 -21
  155. package/dist/commands/hydrogen/env/list.d.ts +0 -18
  156. package/dist/commands/hydrogen/env/pull.d.ts +0 -22
  157. package/dist/commands/hydrogen/g.d.ts +0 -10
  158. package/dist/commands/hydrogen/generate/route.d.ts +0 -32
  159. package/dist/commands/hydrogen/generate/route.test.d.ts +0 -1
  160. package/dist/commands/hydrogen/generate/routes.d.ts +0 -16
  161. package/dist/commands/hydrogen/init.d.ts +0 -24
  162. package/dist/commands/hydrogen/init.test.d.ts +0 -1
  163. package/dist/commands/hydrogen/link.d.ts +0 -23
  164. package/dist/commands/hydrogen/link.test.d.ts +0 -1
  165. package/dist/commands/hydrogen/list.d.ts +0 -21
  166. package/dist/commands/hydrogen/list.test.d.ts +0 -1
  167. package/dist/commands/hydrogen/preview.d.ts +0 -17
  168. package/dist/commands/hydrogen/shortcut.d.ts +0 -9
  169. package/dist/commands/hydrogen/shortcut.test.d.ts +0 -1
  170. package/dist/commands/hydrogen/unlink.d.ts +0 -16
  171. package/dist/commands/hydrogen/unlink.test.d.ts +0 -1
  172. package/dist/create-app.d.ts +0 -1
  173. package/dist/generator-templates/routes/[sitemap.xml].tsx +0 -235
  174. package/dist/generator-templates/routes/account/login.tsx +0 -103
  175. package/dist/generator-templates/routes/account/register.tsx +0 -103
  176. package/dist/generator-templates/routes/cart.tsx +0 -81
  177. package/dist/generator-templates/routes/collections/$collectionHandle.tsx +0 -104
  178. package/dist/generator-templates/routes/collections/index.tsx +0 -102
  179. package/dist/generator-templates/routes/graphiql.tsx +0 -10
  180. package/dist/generator-templates/routes/index.tsx +0 -40
  181. package/dist/generator-templates/routes/pages/$pageHandle.tsx +0 -112
  182. package/dist/generator-templates/routes/policies/$policyHandle.tsx +0 -140
  183. package/dist/generator-templates/routes/policies/index.tsx +0 -117
  184. package/dist/generator-templates/routes/products/$productHandle.tsx +0 -92
  185. package/dist/hooks/init.d.ts +0 -5
  186. package/dist/lib/admin-session.d.ts +0 -6
  187. package/dist/lib/admin-session.js +0 -16
  188. package/dist/lib/admin-session.test.d.ts +0 -1
  189. package/dist/lib/admin-session.test.js +0 -27
  190. package/dist/lib/admin-urls.d.ts +0 -8
  191. package/dist/lib/check-lockfile.d.ts +0 -3
  192. package/dist/lib/check-lockfile.test.d.ts +0 -1
  193. package/dist/lib/check-version.d.ts +0 -16
  194. package/dist/lib/check-version.test.d.ts +0 -1
  195. package/dist/lib/codegen.d.ts +0 -26
  196. package/dist/lib/combined-environment-variables.d.ts +0 -8
  197. package/dist/lib/combined-environment-variables.js +0 -57
  198. package/dist/lib/combined-environment-variables.test.d.ts +0 -1
  199. package/dist/lib/combined-environment-variables.test.js +0 -111
  200. package/dist/lib/config.d.ts +0 -20
  201. package/dist/lib/flags.d.ts +0 -27
  202. package/dist/lib/flags.test.d.ts +0 -1
  203. package/dist/lib/graphql/admin/create-storefront.d.ts +0 -17
  204. package/dist/lib/graphql/admin/fetch-job.d.ts +0 -23
  205. package/dist/lib/graphql/admin/link-storefront.d.ts +0 -14
  206. package/dist/lib/graphql/admin/list-environments.d.ts +0 -21
  207. package/dist/lib/graphql/admin/list-storefronts.d.ts +0 -25
  208. package/dist/lib/graphql/admin/pull-variables.d.ts +0 -21
  209. package/dist/lib/graphql.d.ts +0 -21
  210. package/dist/lib/graphql.js +0 -18
  211. package/dist/lib/graphql.test.d.ts +0 -1
  212. package/dist/lib/log.d.ts +0 -6
  213. package/dist/lib/mini-oxygen.d.ts +0 -22
  214. package/dist/lib/missing-routes.d.ts +0 -8
  215. package/dist/lib/missing-routes.test.d.ts +0 -1
  216. package/dist/lib/missing-storefronts.d.ts +0 -5
  217. package/dist/lib/missing-storefronts.js +0 -18
  218. package/dist/lib/process.d.ts +0 -6
  219. package/dist/lib/pull-environment-variables.d.ts +0 -20
  220. package/dist/lib/pull-environment-variables.js +0 -57
  221. package/dist/lib/pull-environment-variables.test.d.ts +0 -1
  222. package/dist/lib/pull-environment-variables.test.js +0 -174
  223. package/dist/lib/remix-version-interop.d.ts +0 -11
  224. package/dist/lib/remix-version-interop.test.d.ts +0 -1
  225. package/dist/lib/render-errors.d.ts +0 -16
  226. package/dist/lib/shell.d.ts +0 -11
  227. package/dist/lib/shell.test.d.ts +0 -1
  228. package/dist/lib/shop.d.ts +0 -7
  229. package/dist/lib/shop.js +0 -32
  230. package/dist/lib/shop.test.d.ts +0 -1
  231. package/dist/lib/shop.test.js +0 -78
  232. package/dist/lib/shopify-config.d.ts +0 -35
  233. package/dist/lib/shopify-config.test.d.ts +0 -1
  234. package/dist/lib/string.d.ts +0 -3
  235. package/dist/lib/string.test.d.ts +0 -1
  236. package/dist/lib/template-downloader.d.ts +0 -6
  237. package/dist/lib/transpile-ts.d.ts +0 -16
  238. package/dist/lib/user-errors.d.ts +0 -9
  239. package/dist/lib/user-errors.js +0 -11
  240. package/dist/lib/virtual-routes.d.ts +0 -7
  241. package/dist/lib/virtual-routes.test.d.ts +0 -1
  242. /package/dist/{commands/hydrogen/env/list.test.d.ts → lib/setups/css/common.js} +0 -0
  243. /package/dist/{commands/hydrogen/env/pull.test.d.ts → lib/setups/i18n/mock-i18n-types.js} +0 -0
@@ -10,6 +10,7 @@ import { commonFlags, deprecated, flagsToCamelObject } from '../../lib/flags.js'
10
10
  import { checkLockfileStatus } from '../../lib/check-lockfile.js';
11
11
  import { findMissingRoutes } from '../../lib/missing-routes.js';
12
12
  import { warnOnce } from '../../lib/log.js';
13
+ import { codegen } from '../../lib/codegen.js';
13
14
 
14
15
  const LOG_WORKER_BUILT = "\u{1F4E6} Worker built";
15
16
  class Build extends Command {
@@ -25,6 +26,12 @@ class Build extends Command {
25
26
  description: "Disable warning about missing standard routes.",
26
27
  env: "SHOPIFY_HYDROGEN_FLAG_DISABLE_ROUTE_WARNING"
27
28
  }),
29
+ ["codegen-unstable"]: Flags.boolean({
30
+ description: "Generate types for the Storefront API queries found in your project.",
31
+ required: false,
32
+ default: false
33
+ }),
34
+ ["codegen-config-path"]: commonFlags.codegenConfigPath,
28
35
  base: deprecated("--base")(),
29
36
  entry: deprecated("--entry")(),
30
37
  target: deprecated("--target")()
@@ -32,11 +39,17 @@ class Build extends Command {
32
39
  async run() {
33
40
  const { flags } = await this.parse(Build);
34
41
  const directory = flags.path ? resolvePath(flags.path) : process.cwd();
35
- await runBuild({ ...flagsToCamelObject(flags), path: directory });
42
+ await runBuild({
43
+ ...flagsToCamelObject(flags),
44
+ useCodegen: flags["codegen-unstable"],
45
+ path: directory
46
+ });
36
47
  }
37
48
  }
38
49
  async function runBuild({
39
50
  path: appPath,
51
+ useCodegen = false,
52
+ codegenConfigPath,
40
53
  sourcemap = false,
41
54
  disableRouteWarning = false
42
55
  }) {
@@ -68,7 +81,8 @@ async function runBuild({
68
81
  }).catch((thrown) => {
69
82
  logThrown(thrown);
70
83
  process.exit(1);
71
- })
84
+ }),
85
+ useCodegen && codegen({ ...remixConfig, configFilePath: codegenConfigPath })
72
86
  ]);
73
87
  if (process.env.NODE_ENV !== "development") {
74
88
  console.timeEnd(LOG_WORKER_BUILT);
@@ -1,11 +1,10 @@
1
1
  import path from 'path';
2
2
  import Command from '@shopify/cli-kit/node/base-command';
3
- import { AbortError } from '@shopify/cli-kit/node/error';
4
3
  import { renderSuccess } from '@shopify/cli-kit/node/ui';
5
4
  import { Flags } from '@oclif/core';
6
5
  import { getProjectPaths, getRemixConfig } from '../../lib/config.js';
7
6
  import { commonFlags, flagsToCamelObject } from '../../lib/flags.js';
8
- import { patchGqlPluck, generateTypes, normalizeCodegenError } from '../../lib/codegen.js';
7
+ import { codegen } from '../../lib/codegen.js';
9
8
 
10
9
  class Codegen extends Command {
11
10
  static description = "Generate types for the Storefront API queries found in your project.";
@@ -42,29 +41,19 @@ async function runCodegen({
42
41
  }) {
43
42
  const { root } = getProjectPaths(appPath);
44
43
  const remixConfig = await getRemixConfig(root);
45
- await patchGqlPluck();
46
- try {
47
- const generatedFiles = await generateTypes({
48
- ...remixConfig,
49
- configFilePath: codegenConfigPath,
50
- forceSfapiVersion,
51
- watch
44
+ console.log("");
45
+ const generatedFiles = await codegen({
46
+ ...remixConfig,
47
+ configFilePath: codegenConfigPath,
48
+ forceSfapiVersion,
49
+ watch
50
+ });
51
+ if (!watch) {
52
+ renderSuccess({
53
+ headline: "Generated types for GraphQL:",
54
+ body: generatedFiles.map((file) => `- ${file}`).join("\n")
52
55
  });
53
- if (!watch) {
54
- console.log("");
55
- renderSuccess({
56
- headline: "Generated types for GraphQL:",
57
- body: generatedFiles.map((file) => `- ${file}`).join("\n")
58
- });
59
- }
60
- } catch (error) {
61
- const { message, details } = normalizeCodegenError(
62
- error.message,
63
- remixConfig.rootDirectory
64
- );
65
- console.log("");
66
- throw new AbortError(message, details);
67
56
  }
68
57
  }
69
58
 
70
- export { Codegen as default };
59
+ export { Codegen as default, runCodegen };
@@ -1,12 +1,12 @@
1
1
  import path from 'path';
2
2
  import fs from 'fs/promises';
3
- import { outputInfo } from '@shopify/cli-kit/node/output';
3
+ import { outputInfo, outputDebug } from '@shopify/cli-kit/node/output';
4
4
  import { fileExists } from '@shopify/cli-kit/node/fs';
5
5
  import { renderFatalError } from '@shopify/cli-kit/node/ui';
6
6
  import colors from '@shopify/cli-kit/node/colors';
7
7
  import { copyPublicFiles } from './build.js';
8
8
  import { getProjectPaths, getRemixConfig } from '../../lib/config.js';
9
- import { muteDevLogs, warnOnce } from '../../lib/log.js';
9
+ import { muteDevLogs, warnOnce, enhanceH2Logs } from '../../lib/log.js';
10
10
  import { commonFlags, deprecated, flagsToCamelObject } from '../../lib/flags.js';
11
11
  import Command from '@shopify/cli-kit/node/base-command';
12
12
  import { Flags } from '@oclif/core';
@@ -14,7 +14,7 @@ import { startMiniOxygen } from '../../lib/mini-oxygen.js';
14
14
  import { checkHydrogenVersion } from '../../lib/check-version.js';
15
15
  import { addVirtualRoutes } from '../../lib/virtual-routes.js';
16
16
  import { spawnCodegenProcess } from '../../lib/codegen.js';
17
- import { combinedEnvironmentVariables } from '../../lib/combined-environment-variables.js';
17
+ import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
18
18
  import { getConfig } from '../../lib/shopify-config.js';
19
19
 
20
20
  const LOG_REBUILDING = "\u{1F9F1} Rebuilding...";
@@ -29,32 +29,27 @@ class Dev extends Command {
29
29
  required: false,
30
30
  default: false
31
31
  }),
32
- ["codegen-config-path"]: Flags.string({
33
- description: "Specify a path to a codegen configuration file. Defaults to `<root>/codegen.ts` if it exists.",
34
- required: false,
35
- dependsOn: ["codegen-unstable"]
36
- }),
32
+ ["codegen-config-path"]: commonFlags.codegenConfigPath,
37
33
  sourcemap: commonFlags.sourcemap,
38
34
  "disable-virtual-routes": Flags.boolean({
39
35
  description: "Disable rendering fallback routes when a route file doesn't exist.",
40
36
  env: "SHOPIFY_HYDROGEN_FLAG_DISABLE_VIRTUAL_ROUTES",
41
37
  default: false
42
38
  }),
43
- shop: commonFlags.shop,
44
39
  debug: Flags.boolean({
45
40
  description: "Attaches a Node inspector",
46
41
  env: "SHOPIFY_HYDROGEN_FLAG_DEBUG",
47
42
  default: false
48
43
  }),
49
44
  host: deprecated("--host")(),
50
- ["env-branch"]: commonFlags["env-branch"]
45
+ ["env-branch"]: commonFlags.envBranch
51
46
  };
52
47
  async run() {
53
48
  const { flags } = await this.parse(Dev);
54
49
  const directory = flags.path ? path.resolve(flags.path) : process.cwd();
55
50
  await runDev({
56
51
  ...flagsToCamelObject(flags),
57
- codegen: flags["codegen-unstable"],
52
+ useCodegen: flags["codegen-unstable"],
58
53
  path: directory
59
54
  });
60
55
  }
@@ -62,10 +57,9 @@ class Dev extends Command {
62
57
  async function runDev({
63
58
  port,
64
59
  path: appPath,
65
- codegen = false,
60
+ useCodegen = false,
66
61
  codegenConfigPath,
67
62
  disableVirtualRoutes,
68
- shop,
69
63
  envBranch,
70
64
  debug = false,
71
65
  sourcemap = true
@@ -80,19 +74,21 @@ async function runDev({
80
74
  const copyingFiles = copyPublicFiles(publicPath, buildPathClient);
81
75
  const reloadConfig = async () => {
82
76
  const config = await getRemixConfig(root);
83
- return disableVirtualRoutes ? config : addVirtualRoutes(config);
77
+ return disableVirtualRoutes ? config : addVirtualRoutes(config).catch((error) => {
78
+ outputDebug(
79
+ "Could not add virtual routes: " + (error?.stack ?? error?.message ?? error)
80
+ );
81
+ return config;
82
+ });
84
83
  };
85
84
  const getFilePaths = (file) => {
86
85
  const fileRelative = path.relative(root, file);
87
86
  return [fileRelative, path.resolve(root, fileRelative)];
88
87
  };
89
88
  const serverBundleExists = () => fileExists(buildPathWorkerFile);
90
- const hasLinkedStorefront = !!(await getConfig(root))?.storefront?.id;
91
- const environmentVariables = hasLinkedStorefront ? await combinedEnvironmentVariables({
92
- root,
93
- shop,
94
- envBranch
95
- }) : void 0;
89
+ const { shop, storefront } = await getConfig(root);
90
+ const fetchRemote = !!shop && !!storefront?.id;
91
+ const envPromise = getAllEnvironmentVariables({ root, fetchRemote, envBranch });
96
92
  const [{ watch }, { createFileWatchCache }] = await Promise.all([
97
93
  import('@remix-run/dev/dist/compiler/watch.js'),
98
94
  import('@remix-run/dev/dist/compiler/fileWatchCache.js')
@@ -100,38 +96,37 @@ async function runDev({
100
96
  let isInitialBuild = true;
101
97
  let initialBuildDurationMs = 0;
102
98
  let initialBuildStartTimeMs = Date.now();
103
- let isMiniOxygenStarted = false;
99
+ let miniOxygen;
104
100
  async function safeStartMiniOxygen() {
105
- if (isMiniOxygenStarted)
101
+ if (miniOxygen)
106
102
  return;
107
- const miniOxygen = await startMiniOxygen({
103
+ miniOxygen = await startMiniOxygen({
108
104
  root,
109
105
  port,
110
106
  watch: true,
111
107
  buildPathWorkerFile,
112
108
  buildPathClient,
113
- environmentVariables
109
+ env: await envPromise
114
110
  });
115
- isMiniOxygenStarted = true;
111
+ const graphiqlUrl = `${miniOxygen.listeningAt}/graphiql`;
112
+ enhanceH2Logs({ graphiqlUrl, ...remixConfig });
116
113
  miniOxygen.showBanner({
114
+ appName: storefront ? colors.cyan(storefront?.title) : void 0,
117
115
  headlinePrefix: initialBuildDurationMs > 0 ? `Initial build: ${initialBuildDurationMs}ms
118
116
  ` : "",
119
- extraLines: [
120
- colors.dim(
121
- `
122
- View GraphiQL API browser: ${miniOxygen.listeningAt}/graphiql`
123
- )
124
- ]
117
+ extraLines: [colors.dim(`
118
+ View GraphiQL API browser: ${graphiqlUrl}`)]
125
119
  });
120
+ if (useCodegen) {
121
+ spawnCodegenProcess({ ...remixConfig, configFilePath: codegenConfigPath });
122
+ }
126
123
  const showUpgrade = await checkingHydrogenVersion;
127
124
  if (showUpgrade)
128
125
  showUpgrade();
129
126
  }
130
127
  const remixConfig = await reloadConfig();
131
- if (codegen) {
132
- spawnCodegenProcess({ ...remixConfig, configFilePath: codegenConfigPath });
133
- }
134
128
  const fileWatchCache = createFileWatchCache();
129
+ let skipRebuildLogs = false;
135
130
  await watch(
136
131
  {
137
132
  config: remixConfig,
@@ -145,9 +140,9 @@ View GraphiQL API browser: ${miniOxygen.listeningAt}/graphiql`
145
140
  {
146
141
  reloadConfig,
147
142
  onBuildStart() {
148
- if (!isInitialBuild) {
149
- console.time(LOG_REBUILT);
143
+ if (!isInitialBuild && !skipRebuildLogs) {
150
144
  outputInfo(LOG_REBUILDING);
145
+ console.time(LOG_REBUILT);
151
146
  }
152
147
  },
153
148
  async onBuildFinish() {
@@ -155,12 +150,13 @@ View GraphiQL API browser: ${miniOxygen.listeningAt}/graphiql`
155
150
  await copyingFiles;
156
151
  initialBuildDurationMs = Date.now() - initialBuildStartTimeMs;
157
152
  isInitialBuild = false;
158
- } else {
153
+ } else if (!skipRebuildLogs) {
154
+ skipRebuildLogs = false;
159
155
  console.timeEnd(LOG_REBUILT);
160
- if (!isMiniOxygenStarted)
156
+ if (!miniOxygen)
161
157
  console.log("");
162
158
  }
163
- if (!isMiniOxygenStarted) {
159
+ if (!miniOxygen) {
164
160
  if (!await serverBundleExists()) {
165
161
  return renderFatalError({
166
162
  name: "BuildError",
@@ -188,6 +184,16 @@ View GraphiQL API browser: ${miniOxygen.listeningAt}/graphiql`
188
184
  const [relative, absolute] = getFilePaths(file);
189
185
  outputInfo(`
190
186
  \u{1F4C4} File changed: ${relative}`);
187
+ if (relative.endsWith(".env")) {
188
+ skipRebuildLogs = true;
189
+ await miniOxygen.reload({
190
+ env: await getAllEnvironmentVariables({
191
+ root,
192
+ fetchRemote,
193
+ envBranch
194
+ })
195
+ });
196
+ }
191
197
  if (absolute.startsWith(publicPath)) {
192
198
  await copyPublicFiles(
193
199
  absolute,
@@ -2,53 +2,54 @@ import Command from '@shopify/cli-kit/node/base-command';
2
2
  import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
3
3
  import { pluralize } from '@shopify/cli-kit/common/string';
4
4
  import colors from '@shopify/cli-kit/node/colors';
5
- import { outputContent, outputToken, outputNewline, outputInfo } from '@shopify/cli-kit/node/output';
5
+ import { outputNewline, outputInfo, outputContent } from '@shopify/cli-kit/node/output';
6
6
  import { linkStorefront } from '../link.js';
7
7
  import { commonFlags } from '../../../lib/flags.js';
8
- import { getHydrogenShop } from '../../../lib/shop.js';
9
- import { getAdminSession } from '../../../lib/admin-session.js';
10
8
  import { getStorefrontEnvironments } from '../../../lib/graphql/admin/list-environments.js';
11
- import { getConfig } from '../../../lib/shopify-config.js';
12
9
  import { renderMissingLink, renderMissingStorefront } from '../../../lib/render-errors.js';
10
+ import { login } from '../../../lib/auth.js';
11
+ import { getCliCommand } from '../../../lib/shell.js';
13
12
 
14
13
  class EnvList extends Command {
15
14
  static description = "List the environments on your linked Hydrogen storefront.";
16
15
  static flags = {
17
- path: commonFlags.path,
18
- shop: commonFlags.shop
16
+ path: commonFlags.path
19
17
  };
20
18
  async run() {
21
19
  const { flags } = await this.parse(EnvList);
22
- await listEnvironments(flags);
20
+ await runEnvList(flags);
23
21
  }
24
22
  }
25
- async function listEnvironments({ path, shop: flagShop }) {
26
- const shop = await getHydrogenShop({ path, shop: flagShop });
27
- const adminSession = await getAdminSession(shop);
28
- const actualPath = path ?? process.cwd();
29
- let configStorefront = (await getConfig(actualPath)).storefront;
23
+ async function runEnvList({ path: root = process.cwd() }) {
24
+ const [{ session, config }, cliCommand] = await Promise.all([
25
+ login(root),
26
+ getCliCommand()
27
+ ]);
28
+ let configStorefront = config.storefront;
30
29
  if (!configStorefront?.id) {
31
- renderMissingLink({ adminSession });
30
+ renderMissingLink({ session, cliCommand });
32
31
  const runLink = await renderConfirmationPrompt({
33
- message: outputContent`Run ${outputToken.genericShellCommand(
34
- `npx shopify hydrogen link`
35
- )}?`.value
32
+ message: ["Run", { command: `${cliCommand} link` }, "?"]
36
33
  });
37
34
  if (!runLink) {
38
35
  return;
39
36
  }
40
- await linkStorefront({ path, shop: flagShop, silent: true });
37
+ configStorefront = await linkStorefront(root, session, config, {
38
+ cliCommand
39
+ });
41
40
  }
42
- configStorefront = (await getConfig(actualPath)).storefront;
43
- if (!configStorefront) {
41
+ if (!configStorefront)
44
42
  return;
45
- }
46
- const { storefront } = await getStorefrontEnvironments(
47
- adminSession,
43
+ const storefront = await getStorefrontEnvironments(
44
+ session,
48
45
  configStorefront.id
49
46
  );
50
47
  if (!storefront) {
51
- renderMissingStorefront({ adminSession, storefront: configStorefront });
48
+ renderMissingStorefront({
49
+ session,
50
+ storefront: configStorefront,
51
+ cliCommand
52
+ });
52
53
  return;
53
54
  }
54
55
  const previewEnvironmentIndex = storefront.environments.findIndex(
@@ -91,4 +92,4 @@ const pluralizedEnvironments = ({
91
92
  );
92
93
  };
93
94
 
94
- export { EnvList as default, listEnvironments };
95
+ export { EnvList as default, runEnvList };
@@ -3,11 +3,10 @@ import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
3
3
  import { inTemporaryDirectory } from '@shopify/cli-kit/node/fs';
4
4
  import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
5
5
  import { getStorefrontEnvironments } from '../../../lib/graphql/admin/list-environments.js';
6
- import { getAdminSession } from '../../../lib/admin-session.js';
7
- import { getConfig } from '../../../lib/shopify-config.js';
6
+ import { login } from '../../../lib/auth.js';
8
7
  import { renderMissingLink, renderMissingStorefront } from '../../../lib/render-errors.js';
9
8
  import { linkStorefront } from '../link.js';
10
- import { listEnvironments } from './list.js';
9
+ import { runEnvList } from './list.js';
11
10
 
12
11
  const SHOP = "my-shop";
13
12
  vi.mock("@shopify/cli-kit/node/ui", async () => {
@@ -18,20 +17,25 @@ vi.mock("@shopify/cli-kit/node/ui", async () => {
18
17
  };
19
18
  });
20
19
  vi.mock("../link.js");
21
- vi.mock("../../../lib/admin-session.js");
20
+ vi.mock("../../../lib/auth.js");
22
21
  vi.mock("../../../lib/shopify-config.js");
23
22
  vi.mock("../../../lib/render-errors.js");
24
- vi.mock("../../../lib/graphql/admin/list-environments.js", () => {
25
- return { getStorefrontEnvironments: vi.fn() };
26
- });
27
- vi.mock("../../../lib/shop.js", () => ({
28
- getHydrogenShop: () => SHOP
29
- }));
23
+ vi.mock("../../../lib/graphql/admin/list-environments.js");
24
+ vi.mock("../../../lib/shell.js", () => ({ getCliCommand: () => "h2" }));
30
25
  describe("listEnvironments", () => {
31
26
  const ADMIN_SESSION = {
32
27
  token: "abc123",
33
28
  storeFqdn: SHOP
34
29
  };
30
+ const SHOPIFY_CONFIG = {
31
+ shop: SHOP,
32
+ shopName: "My Shop",
33
+ email: "email",
34
+ storefront: {
35
+ id: "gid://shopify/HydrogenStorefront/1",
36
+ title: "Existing Link"
37
+ }
38
+ };
35
39
  const PRODUCTION_ENVIRONMENT = {
36
40
  id: "gid://shopify/HydrogenStorefrontEnvironment/1",
37
41
  branch: "main",
@@ -57,44 +61,39 @@ describe("listEnvironments", () => {
57
61
  url: null
58
62
  };
59
63
  beforeEach(async () => {
60
- vi.mocked(getAdminSession).mockResolvedValue(ADMIN_SESSION);
61
- vi.mocked(getConfig).mockResolvedValue({
62
- storefront: {
63
- id: "gid://shopify/HydrogenStorefront/1",
64
- title: "Existing Link"
65
- }
64
+ vi.mocked(login).mockResolvedValue({
65
+ session: ADMIN_SESSION,
66
+ config: SHOPIFY_CONFIG
66
67
  });
67
68
  vi.mocked(getStorefrontEnvironments).mockResolvedValue({
68
- storefront: {
69
- id: "gid://shopify/HydrogenStorefront/1",
70
- productionUrl: "https://example.com",
71
- environments: [
72
- PRODUCTION_ENVIRONMENT,
73
- CUSTOM_ENVIRONMENT,
74
- PREVIEW_ENVIRONMENT
75
- ]
76
- }
69
+ id: "gid://shopify/HydrogenStorefront/1",
70
+ productionUrl: "https://example.com",
71
+ environments: [
72
+ PRODUCTION_ENVIRONMENT,
73
+ CUSTOM_ENVIRONMENT,
74
+ PREVIEW_ENVIRONMENT
75
+ ]
77
76
  });
78
77
  });
79
78
  afterEach(() => {
80
79
  vi.resetAllMocks();
81
80
  mockAndCaptureOutput().clear();
82
81
  });
83
- it("makes a GraphQL call to fetch environment variables", async () => {
82
+ it("fetchs environment variables", async () => {
84
83
  await inTemporaryDirectory(async (tmpDir) => {
85
- await listEnvironments({ path: tmpDir });
84
+ await runEnvList({ path: tmpDir });
86
85
  expect(getStorefrontEnvironments).toHaveBeenCalledWith(
87
86
  ADMIN_SESSION,
88
- "gid://shopify/HydrogenStorefront/1"
87
+ SHOPIFY_CONFIG.storefront.id
89
88
  );
90
89
  });
91
90
  });
92
91
  it("lists the environments", async () => {
93
92
  await inTemporaryDirectory(async (tmpDir) => {
94
93
  const output = mockAndCaptureOutput();
95
- await listEnvironments({ path: tmpDir });
94
+ await runEnvList({ path: tmpDir });
96
95
  expect(output.info()).toMatch(
97
- /Showing 3 environments for the Hydrogen storefront Existing Link/
96
+ /Showing 3 environments for the Hydrogen storefront Existing Link/i
98
97
  );
99
98
  expect(output.info()).toMatch(/Production \(Branch: main\)/);
100
99
  expect(output.info()).toMatch(/https:\/\/example\.com/);
@@ -105,39 +104,43 @@ describe("listEnvironments", () => {
105
104
  });
106
105
  describe("when there is no linked storefront", () => {
107
106
  beforeEach(() => {
108
- vi.mocked(getConfig).mockResolvedValue({
109
- storefront: void 0
107
+ vi.mocked(login).mockResolvedValue({
108
+ session: ADMIN_SESSION,
109
+ config: {
110
+ ...SHOPIFY_CONFIG,
111
+ storefront: void 0
112
+ }
110
113
  });
111
114
  });
112
115
  it("calls renderMissingLink", async () => {
113
116
  await inTemporaryDirectory(async (tmpDir) => {
114
- await listEnvironments({ path: tmpDir });
117
+ await runEnvList({ path: tmpDir });
115
118
  expect(renderMissingLink).toHaveBeenCalledOnce();
116
119
  });
117
120
  });
118
121
  it("prompts the user to create a link", async () => {
119
122
  vi.mocked(renderConfirmationPrompt).mockResolvedValue(true);
120
123
  await inTemporaryDirectory(async (tmpDir) => {
121
- await listEnvironments({ path: tmpDir });
124
+ await runEnvList({ path: tmpDir });
122
125
  expect(renderConfirmationPrompt).toHaveBeenCalledWith({
123
- message: expect.stringMatching(/Run .*npx shopify hydrogen link.*\?/)
124
- });
125
- expect(linkStorefront).toHaveBeenCalledWith({
126
- path: tmpDir,
127
- silent: true
126
+ message: expect.arrayContaining([{ command: "h2 link" }])
128
127
  });
128
+ expect(linkStorefront).toHaveBeenCalledWith(
129
+ tmpDir,
130
+ ADMIN_SESSION,
131
+ { ...SHOPIFY_CONFIG, storefront: void 0 },
132
+ expect.anything()
133
+ );
129
134
  });
130
135
  });
131
136
  });
132
137
  describe("when there is no matching storefront in the shop", () => {
133
138
  beforeEach(() => {
134
- vi.mocked(getStorefrontEnvironments).mockResolvedValue({
135
- storefront: null
136
- });
139
+ vi.mocked(getStorefrontEnvironments).mockResolvedValue(null);
137
140
  });
138
141
  it("calls renderMissingStorefront", async () => {
139
142
  await inTemporaryDirectory(async (tmpDir) => {
140
- await listEnvironments({ path: tmpDir });
143
+ await runEnvList({ path: tmpDir });
141
144
  expect(renderMissingStorefront).toHaveBeenCalledOnce();
142
145
  });
143
146
  });
@@ -1,47 +1,78 @@
1
1
  import { diffLines } from 'diff';
2
2
  import Command from '@shopify/cli-kit/node/base-command';
3
- import { renderInfo, renderConfirmationPrompt, renderWarning, renderSuccess } from '@shopify/cli-kit/node/ui';
4
- import { outputContent, outputToken } from '@shopify/cli-kit/node/output';
3
+ import { renderConfirmationPrompt, renderInfo, renderWarning, renderSuccess } from '@shopify/cli-kit/node/ui';
4
+ import { outputContent, outputToken, outputInfo } from '@shopify/cli-kit/node/output';
5
5
  import { fileExists, readFile, writeFile } from '@shopify/cli-kit/node/fs';
6
6
  import { resolvePath } from '@shopify/cli-kit/node/path';
7
7
  import { patchEnvFile } from '@shopify/cli-kit/node/dot-env';
8
8
  import colors from '@shopify/cli-kit/node/colors';
9
9
  import { commonFlags, flagsToCamelObject } from '../../../lib/flags.js';
10
- import { pullRemoteEnvironmentVariables } from '../../../lib/pull-environment-variables.js';
11
- import { getConfig } from '../../../lib/shopify-config.js';
10
+ import { login } from '../../../lib/auth.js';
11
+ import { getCliCommand } from '../../../lib/shell.js';
12
+ import { renderMissingLink, renderMissingStorefront } from '../../../lib/render-errors.js';
13
+ import { linkStorefront } from '../link.js';
14
+ import { getStorefrontEnvVariables } from '../../../lib/graphql/admin/pull-variables.js';
12
15
 
13
16
  class EnvPull extends Command {
14
17
  static description = "Populate your .env with variables from your Hydrogen storefront.";
15
18
  static flags = {
16
- ["env-branch"]: commonFlags["env-branch"],
19
+ ["env-branch"]: commonFlags.envBranch,
17
20
  path: commonFlags.path,
18
- shop: commonFlags.shop,
19
21
  force: commonFlags.force
20
22
  };
21
23
  async run() {
22
24
  const { flags } = await this.parse(EnvPull);
23
- await pullVariables({ ...flagsToCamelObject(flags) });
25
+ await runEnvPull({ ...flagsToCamelObject(flags) });
24
26
  }
25
27
  }
26
- async function pullVariables({
28
+ async function runEnvPull({
27
29
  envBranch,
28
- force,
29
- path,
30
- shop: flagShop
30
+ path: root = process.cwd(),
31
+ force
31
32
  }) {
32
- const actualPath = path ?? process.cwd();
33
- const environmentVariables = await pullRemoteEnvironmentVariables({
34
- root: actualPath,
35
- flagShop,
33
+ const [{ session, config }, cliCommand] = await Promise.all([
34
+ login(root),
35
+ getCliCommand()
36
+ ]);
37
+ if (!config.storefront?.id) {
38
+ renderMissingLink({ session, cliCommand });
39
+ const runLink = await renderConfirmationPrompt({
40
+ message: outputContent`Run ${outputToken.genericShellCommand(
41
+ `${cliCommand} link`
42
+ )}?`.value
43
+ });
44
+ if (!runLink)
45
+ return;
46
+ config.storefront = await linkStorefront(root, session, config, {
47
+ cliCommand
48
+ });
49
+ }
50
+ if (!config.storefront?.id)
51
+ return;
52
+ const storefront = await getStorefrontEnvVariables(
53
+ session,
54
+ config.storefront.id,
36
55
  envBranch
37
- });
38
- if (!environmentVariables.length) {
56
+ );
57
+ if (!storefront) {
58
+ renderMissingStorefront({
59
+ session,
60
+ storefront: config.storefront,
61
+ cliCommand
62
+ });
63
+ return;
64
+ }
65
+ if (!storefront.environmentVariables.length) {
66
+ outputInfo(`No environment variables found.`);
39
67
  return;
40
68
  }
69
+ const variables = storefront.environmentVariables;
70
+ if (!variables.length)
71
+ return;
41
72
  const fileName = colors.whiteBright(`.env`);
42
- const dotEnvPath = resolvePath(actualPath, ".env");
73
+ const dotEnvPath = resolvePath(root, ".env");
43
74
  const fetchedEnv = {};
44
- environmentVariables.forEach(({ isSecret, key, value }) => {
75
+ variables.forEach(({ isSecret, key, value }) => {
45
76
  fetchedEnv[key] = isSecret ? `""` : value;
46
77
  });
47
78
  if (await fileExists(dotEnvPath) && !force) {
@@ -70,13 +101,10 @@ Continue?`.value
70
101
  const newEnv = patchEnvFile(null, fetchedEnv);
71
102
  await writeFile(dotEnvPath, newEnv);
72
103
  }
73
- const hasSecretVariables = environmentVariables.some(
74
- ({ isSecret }) => isSecret
75
- );
104
+ const hasSecretVariables = variables.some(({ isSecret }) => isSecret);
76
105
  if (hasSecretVariables) {
77
- const { storefront: configStorefront } = await getConfig(actualPath);
78
106
  renderWarning({
79
- body: `${configStorefront.title} contains environment variables marked as secret, so their values weren\u2019t pulled.`
107
+ body: `${config.storefront.title} contains environment variables marked as secret, so their values weren\u2019t pulled.`
80
108
  });
81
109
  }
82
110
  renderSuccess({
@@ -84,4 +112,4 @@ Continue?`.value
84
112
  });
85
113
  }
86
114
 
87
- export { EnvPull as default, pullVariables };
115
+ export { EnvPull as default, runEnvPull };