@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
@@ -7,22 +7,21 @@ import { getCliCommand } from '../../../lib/shell.js';
7
7
  import { resolvePath } from '@shopify/cli-kit/node/path';
8
8
  import { renderConfirmationPrompt, renderSelectPrompt, renderInfo, renderSuccess } from '@shopify/cli-kit/node/ui';
9
9
  import { outputContent, outputToken, outputWarn } from '@shopify/cli-kit/node/output';
10
+ import { orderEnvironmentsBySafety, findEnvironmentOrThrow, createEnvironmentCliChoiceLabel } from '../../../lib/common.js';
10
11
  import { renderMissingLink } from '../../../lib/render-errors.js';
11
12
  import { getStorefrontEnvironments } from '../../../lib/graphql/admin/list-environments.js';
12
13
  import { linkStorefront } from '../link.js';
13
14
  import { getStorefrontEnvVariables } from '../../../lib/graphql/admin/pull-variables.js';
14
15
  import { pushStorefrontEnvVariables } from '../../../lib/graphql/admin/push-variables.js';
15
16
  import { AbortError } from '@shopify/cli-kit/node/error';
16
- import { readAndParseDotEnv } from '@shopify/cli-kit/node/dot-env';
17
+ import { readAndParseDotEnv, createDotEnvFileLine } from '@shopify/cli-kit/node/dot-env';
17
18
 
18
19
  class EnvPush extends Command {
19
20
  static description = "Push environment variables from the local .env file to your linked Hydrogen storefront.";
20
- static hidden = true;
21
21
  static flags = {
22
22
  ...commonFlags.env,
23
23
  "env-file": Flags.string({
24
- description: "Specify the environment variable file name. Default value is '.env'.",
25
- env: "SHOPIFY_HYDROGEN_ENVIRONMENT_FILENAME"
24
+ description: "Path to an environment file to override existing environment variables for the selected environment. Defaults to the '.env' located in your project path `--path`."
26
25
  }),
27
26
  ...commonFlags.path
28
27
  };
@@ -32,12 +31,12 @@ class EnvPush extends Command {
32
31
  }
33
32
  }
34
33
  async function runEnvPush({
35
- env: environmentName,
36
- envFile = ".env",
34
+ env: envHandle,
35
+ envFile,
37
36
  path = process.cwd()
38
37
  }) {
39
- let validatedEnvironment = {};
40
- const dotEnvPath = resolvePath(path, envFile);
38
+ let validatedEnvironment;
39
+ const dotEnvPath = envFile || resolvePath(path, ".env");
41
40
  const { variables: localVariables } = await readAndParseDotEnv(dotEnvPath);
42
41
  const [{ session, config }, cliCommand] = await Promise.all([
43
42
  login(path),
@@ -62,69 +61,43 @@ async function runEnvPush({
62
61
  if (!environmentsData) {
63
62
  throw new AbortError("Failed to fetch environments");
64
63
  }
65
- const environments = [
66
- ...environmentsData.filter((environment) => environment.type === "PREVIEW"),
67
- ...environmentsData.filter((environment) => environment.type === "CUSTOM"),
68
- ...environmentsData.filter(
69
- (environment) => environment.type === "PRODUCTION"
70
- )
71
- ];
64
+ const environments = orderEnvironmentsBySafety(environmentsData);
72
65
  if (environments.length === 0) {
73
66
  throw new AbortError("No environments found");
74
67
  }
75
- if (environmentName) {
76
- const matchedEnvironments = environments.filter(
77
- ({ name }) => name === environmentName
78
- );
79
- if (matchedEnvironments.length === 0) {
80
- throw new AbortError(
81
- "Environment not found",
82
- `We could not find an environment matching the name '${environmentName}'.`
83
- );
84
- } else if (matchedEnvironments.length === 1) {
85
- const { id, name, branch, type } = matchedEnvironments[0] ?? {};
86
- validatedEnvironment = { id, name, branch, type };
87
- } else {
88
- const selection = await renderSelectPrompt({
89
- message: `There were multiple environments found with the name ${environmentName}:`,
90
- choices: [
91
- ...matchedEnvironments.map(({ id: id2, name: name2, branch: branch2, type: type2, url }) => ({
92
- label: `${name2} (${branch2}) ${type2} ${url}`,
93
- value: id2
94
- }))
95
- ]
96
- });
97
- const { id, name, branch, type } = matchedEnvironments.find(({ id: id2 }) => id2 === selection) ?? {};
98
- validatedEnvironment = { id, name, branch, type };
99
- }
68
+ if (envHandle) {
69
+ validatedEnvironment = findEnvironmentOrThrow(environments, envHandle);
100
70
  } else {
101
71
  const choices = [
102
- ...environments.map(({ id: id2, name: name2, branch: branch2 }) => ({
103
- label: branch2 ? `${name2} (${branch2})` : name2,
104
- value: id2
105
- }))
72
+ ...environments.map(({ id, name, branch, handle }) => {
73
+ return {
74
+ label: createEnvironmentCliChoiceLabel(name, handle, branch),
75
+ value: id
76
+ };
77
+ })
106
78
  ];
107
79
  const pushToBranchSelection = await renderSelectPrompt({
108
- message: "Select a set of environment variables to overwrite:",
80
+ message: "Select an environment to overwrite its environment variables:",
109
81
  choices
110
82
  });
111
- const { id, name, branch, type } = environments.find(({ id: id2 }) => id2 === pushToBranchSelection) ?? {};
112
- validatedEnvironment = { id, name, branch, type };
83
+ validatedEnvironment = environments.find(
84
+ ({ id }) => id === pushToBranchSelection
85
+ );
113
86
  }
114
87
  const { environmentVariables = [] } = await getStorefrontEnvVariables(
115
88
  session,
116
89
  config.storefront.id,
117
- validatedEnvironment.branch ?? void 0
90
+ validatedEnvironment.handle
118
91
  ) ?? {};
119
92
  const remoteVars = environmentVariables.filter(
120
93
  ({ isSecret, readOnly }) => !isSecret && !readOnly
121
94
  );
122
- const comparableRemoteVars = remoteVars.sort((a, b) => a.key.localeCompare(b.key)).map(({ key, value }) => `${key}=${value}`).join("\n") + "\n";
95
+ const comparableRemoteVars = remoteVars.sort((a, b) => a.key.localeCompare(b.key)).map(({ key, value }) => createDotEnvFileLine(key, value)).join("\n") + "\n";
123
96
  const compareableLocalVars = Object.keys(localVariables).sort((a, b) => a.localeCompare(b)).reduce((acc, key) => {
124
97
  const { isSecret, readOnly } = environmentVariables.find((variable) => variable.key === key) ?? {};
125
98
  if (isSecret || readOnly)
126
99
  return acc;
127
- return [...acc, `${key}=${localVariables[key]}`];
100
+ return [...acc, createDotEnvFileLine(key, localVariables[key])];
128
101
  }, []).join("\n") + "\n";
129
102
  if (!validatedEnvironment.name)
130
103
  throw new AbortError("Missing environment name");
@@ -8,6 +8,7 @@ import { ALL_ROUTE_CHOICES, generateRoutes } from '../../../lib/setups/routes/ge
8
8
  import { isV1RouteConventionInstalled } from '../../../lib/remix-version-interop.js';
9
9
 
10
10
  class GenerateRoute extends Command {
11
+ static descriptionWithMarkdown = `Generates a set of default routes from the starter template.`;
11
12
  static description = "Generates a standard Shopify route.";
12
13
  static flags = {
13
14
  adapter: Flags.string({
@@ -14,6 +14,7 @@ import { LANGUAGES } from '../../lib/onboarding/common.js';
14
14
 
15
15
  const FLAG_MAP = { f: "force" };
16
16
  class Init extends Command {
17
+ static descriptionWithMarkdown = "Creates a new Hydrogen storefront.";
17
18
  static description = "Creates a new Hydrogen storefront.";
18
19
  static flags = {
19
20
  ...commonFlags.force,
@@ -50,29 +51,55 @@ class Init extends Command {
50
51
  env: "SHOPIFY_HYDROGEN_FLAG_GIT",
51
52
  default: true,
52
53
  allowNo: true
54
+ }),
55
+ quickstart: Flags.boolean({
56
+ description: "Scaffolds a new Hydrogen project with a set of sensible defaults.",
57
+ env: "SHOPIFY_HYDROGEN_FLAG_QUICKSTART",
58
+ default: false
59
+ }),
60
+ "package-manager": Flags.string({
61
+ env: "SHOPIFY_HYDROGEN_FLAG_PACKAGE_MANAGER",
62
+ hidden: true,
63
+ options: ["npm", "yarn", "pnpm", "unknown"]
53
64
  })
54
65
  };
55
66
  async run() {
56
- const {
57
- flags: { markets, ..._flags }
58
- } = await this.parse(Init);
59
- const flags = { ..._flags, i18n: markets };
60
- if (flags.i18n && !I18N_CHOICES.includes(flags.i18n)) {
61
- throw new AbortError(
62
- `Invalid URL structure strategy: ${flags.i18n}. Must be one of ${I18N_CHOICES.join(", ")}`
63
- );
64
- }
65
- if (flags.styling && !STYLING_CHOICES.includes(flags.styling)) {
66
- throw new AbortError(
67
- `Invalid styling strategy: ${flags.styling}. Must be one of ${STYLING_CHOICES.join(", ")}`
68
- );
69
- }
67
+ const { flags } = await this.parse(Init);
70
68
  await runInit(flagsToCamelObject(flags));
71
69
  }
72
70
  }
73
- async function runInit(options = parseProcessFlags(process.argv, FLAG_MAP)) {
71
+ async function runInit({
72
+ markets,
73
+ ...options
74
+ } = parseProcessFlags(
75
+ process.argv,
76
+ FLAG_MAP
77
+ )) {
74
78
  supressNodeExperimentalWarnings();
79
+ if (!options.i18n && markets) {
80
+ options.i18n = markets;
81
+ }
82
+ if (options.i18n && !I18N_CHOICES.includes(options.i18n)) {
83
+ throw new AbortError(
84
+ `Invalid URL structure strategy: ${options.i18n}. Must be one of ${I18N_CHOICES.join(", ")}`
85
+ );
86
+ }
87
+ if (options.styling && !STYLING_CHOICES.includes(options.styling)) {
88
+ throw new AbortError(
89
+ `Invalid styling strategy: ${options.styling}. Must be one of ${STYLING_CHOICES.join(", ")}`
90
+ );
91
+ }
75
92
  options.git ??= true;
93
+ if (options.quickstart) {
94
+ options.i18n ||= "none";
95
+ options.installDeps ||= true;
96
+ options.language ||= "js";
97
+ options.mockShop ||= true;
98
+ options.path ||= "./hydrogen-quickstart";
99
+ options.routes ||= true;
100
+ options.shortcut ||= true;
101
+ options.styling ||= "tailwind";
102
+ }
76
103
  const showUpgrade = await checkHydrogenVersion(
77
104
  // Resolving the CLI package from a local directory might fail because
78
105
  // this code could be run from a global dependency (e.g. on `npm create`).
@@ -81,14 +108,15 @@ async function runInit(options = parseProcessFlags(process.argv, FLAG_MAP)) {
81
108
  "cli"
82
109
  );
83
110
  if (showUpgrade) {
84
- const packageManager = packageManagerFromUserAgent();
111
+ const packageManager = options.packageManager ?? packageManagerFromUserAgent();
85
112
  showUpgrade(
86
113
  packageManager === "unknown" ? "" : `Please use the latest version with \`${packageManager} create @shopify/hydrogen@latest\``
87
114
  );
88
115
  }
89
116
  const controller = new AbortController();
90
117
  try {
91
- return options.template ? await setupRemoteTemplate(options, controller) : await setupLocalStarterTemplate(options, controller);
118
+ const template = options.template;
119
+ return template ? await setupRemoteTemplate({ ...options, template }, controller) : await setupLocalStarterTemplate(options, controller);
92
120
  } catch (error) {
93
121
  controller.abort();
94
122
  throw error;
@@ -11,9 +11,14 @@ import { waitForJob } from '../../lib/graphql/admin/fetch-job.js';
11
11
  import { titleize } from '../../lib/string.js';
12
12
  import { getCliCommand } from '../../lib/shell.js';
13
13
  import { login } from '../../lib/auth.js';
14
- import { handleStorefrontSelection } from '../../lib/onboarding/common.js';
14
+ import { handleStorefrontSelection, generateRandomName } from '../../lib/onboarding/common.js';
15
15
 
16
16
  class Link extends Command {
17
+ static descriptionWithMarkdown = `Links your local development environment to a remote Hydrogen storefront. You can link an unlimited number of development environments to a single Hydrogen storefront.
18
+
19
+ Linking to a Hydrogen storefront enables you to run [dev](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-dev) and automatically inject your linked Hydrogen storefront's environment variables directly into the server runtime.
20
+
21
+ After you run the \`link\` command, you can access the [env list](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-env-list), [env pull](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-env-pull), and [unlink](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-unlink) commands.`;
17
22
  static description = "Link a local project to one of your shop's Hydrogen storefronts.";
18
23
  static flags = {
19
24
  ...commonFlags.force,
@@ -96,17 +101,28 @@ async function linkStorefront(root, session, config, {
96
101
  } else {
97
102
  selectedStorefront = await handleStorefrontSelection(storefronts);
98
103
  if (!selectedStorefront) {
99
- selectedStorefront = await createNewStorefront(root, session);
104
+ selectedStorefront = await createNewStorefront(
105
+ root,
106
+ session,
107
+ storefronts
108
+ );
100
109
  }
101
110
  }
102
111
  await setStorefront(root, selectedStorefront);
103
112
  return selectedStorefront;
104
113
  }
105
- async function createNewStorefront(root, session) {
114
+ async function createNewStorefront(root, session, storefronts) {
106
115
  const projectDirectory = basename(root);
116
+ let defaultProjectName = titleize(projectDirectory);
117
+ const nameAlreadyUsed = storefronts.some(
118
+ ({ title }) => title === defaultProjectName
119
+ );
120
+ if (nameAlreadyUsed) {
121
+ defaultProjectName = generateRandomName();
122
+ }
107
123
  const projectName = await renderTextPrompt({
108
124
  message: "New storefront name",
109
- defaultValue: titleize(projectDirectory)
125
+ defaultValue: defaultProjectName
110
126
  });
111
127
  let storefront;
112
128
  let jobId;
@@ -11,6 +11,7 @@ import { login } from '../../lib/auth.js';
11
11
  import { getCliCommand } from '../../lib/shell.js';
12
12
 
13
13
  class List extends Command {
14
+ static descriptionWithMarkdown = "Lists all remote Hydrogen storefronts available to link to your local development environment.";
14
15
  static description = "Returns a list of Hydrogen storefronts available on a given shop.";
15
16
  static flags = {
16
17
  ...commonFlags.path
@@ -3,6 +3,7 @@ import { commonFlags } from '../../lib/flags.js';
3
3
  import { login, renderLoginSuccess } from '../../lib/auth.js';
4
4
 
5
5
  class Login extends Command {
6
+ static descriptionWithMarkdown = "Logs in to the specified shop and saves the shop domain to the project.";
6
7
  static description = "Login to your Shopify account.";
7
8
  static flags = {
8
9
  ...commonFlags.path,
@@ -4,6 +4,7 @@ import { commonFlags } from '../../lib/flags.js';
4
4
  import { logout } from '../../lib/auth.js';
5
5
 
6
6
  class Logout extends Command {
7
+ static descriptionWithMarkdown = "Log out from the current shop.";
7
8
  static description = "Logout of your local session.";
8
9
  static flags = {
9
10
  ...commonFlags.path
@@ -1,25 +1,27 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
- import { muteDevLogs } from '../../lib/log.js';
3
- import { getProjectPaths } from '../../lib/remix-config.js';
4
- import { commonFlags, deprecated, flagsToCamelObject } from '../../lib/flags.js';
2
+ import { setH2OVerbose, isH2Verbose, muteDevLogs } from '../../lib/log.js';
3
+ import { getProjectPaths, hasRemixConfigFile } from '../../lib/remix-config.js';
4
+ import { commonFlags, deprecated, flagsToCamelObject, DEFAULT_APP_PORT } from '../../lib/flags.js';
5
5
  import { startMiniOxygen } from '../../lib/mini-oxygen/index.js';
6
6
  import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
7
7
  import { getConfig } from '../../lib/shopify-config.js';
8
8
  import { findPort } from '../../lib/find-port.js';
9
- import { fileExists } from '@shopify/cli-kit/node/fs';
10
9
  import { joinPath } from '@shopify/cli-kit/node/path';
11
10
  import { getViteConfig } from '../../lib/vite-config.js';
12
11
 
13
12
  class Preview extends Command {
13
+ static descriptionWithMarkdown = "Runs a server in your local development environment that serves your Hydrogen app's production build. Requires running the [build](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-build) command first.";
14
14
  static description = "Runs a Hydrogen storefront in an Oxygen worker for production.";
15
15
  static flags = {
16
16
  ...commonFlags.path,
17
17
  ...commonFlags.port,
18
18
  worker: deprecated("--worker", { isBoolean: true }),
19
19
  ...commonFlags.legacyRuntime,
20
+ ...commonFlags.env,
20
21
  ...commonFlags.envBranch,
21
22
  ...commonFlags.inspectorPort,
22
- ...commonFlags.debug
23
+ ...commonFlags.debug,
24
+ ...commonFlags.verbose
23
25
  };
24
26
  async run() {
25
27
  const { flags } = await this.parse(Preview);
@@ -32,31 +34,44 @@ async function runPreview({
32
34
  port: appPort,
33
35
  path: appPath,
34
36
  legacyRuntime = false,
37
+ env: envHandle,
35
38
  envBranch,
36
39
  inspectorPort,
37
- debug
40
+ debug,
41
+ verbose
38
42
  }) {
39
43
  if (!process.env.NODE_ENV)
40
44
  process.env.NODE_ENV = "production";
41
- muteDevLogs({ workerReload: false });
42
- let { root, buildPathWorkerFile, buildPathClient } = getProjectPaths(appPath);
43
- if (!await fileExists(joinPath(root, buildPathWorkerFile))) {
45
+ if (verbose)
46
+ setH2OVerbose();
47
+ if (!isH2Verbose())
48
+ muteDevLogs();
49
+ let { root, buildPath, buildPathWorkerFile, buildPathClient } = getProjectPaths(appPath);
50
+ if (!await hasRemixConfigFile(root)) {
44
51
  const maybeResult = await getViteConfig(root).catch(() => null);
45
- if (maybeResult)
46
- buildPathWorkerFile = maybeResult.serverOutFile;
52
+ buildPathWorkerFile = maybeResult?.serverOutFile ?? joinPath(buildPath, "server", "index.js");
47
53
  }
48
54
  const { shop, storefront } = await getConfig(root);
49
55
  const fetchRemote = !!shop && !!storefront?.id;
50
- const env = await getAllEnvironmentVariables({ root, fetchRemote, envBranch });
51
- appPort = legacyRuntime ? appPort : await findPort(appPort);
52
- inspectorPort = debug ? await findPort(inspectorPort) : inspectorPort;
56
+ const { allVariables, logInjectedVariables } = await getAllEnvironmentVariables(
57
+ {
58
+ root,
59
+ fetchRemote,
60
+ envBranch,
61
+ envHandle
62
+ }
63
+ );
64
+ if (!appPort) {
65
+ appPort = await findPort(DEFAULT_APP_PORT);
66
+ }
53
67
  const assetsPort = legacyRuntime ? 0 : await findPort(appPort + 100);
68
+ logInjectedVariables();
54
69
  const miniOxygen = await startMiniOxygen(
55
70
  {
56
71
  root,
57
- port: appPort,
72
+ appPort,
58
73
  assetsPort,
59
- env,
74
+ env: allVariables,
60
75
  buildPathClient,
61
76
  buildPathWorkerFile,
62
77
  inspectorPort,
@@ -4,10 +4,12 @@ import Command from '@shopify/cli-kit/node/base-command';
4
4
  import { renderTasks, renderSuccess } from '@shopify/cli-kit/node/ui';
5
5
  import { getPackageManager, installNodeModules } from '@shopify/cli-kit/node/node-package-manager';
6
6
  import { Args } from '@oclif/core';
7
- import { getRemixConfig } from '../../../lib/remix-config.js';
7
+ import { hasRemixConfigFile, getRemixConfig } from '../../../lib/remix-config.js';
8
8
  import { SETUP_CSS_STRATEGIES, renderCssPrompt, setupCssStrategy, CSS_STRATEGY_NAME_MAP } from '../../../lib/setups/css/index.js';
9
+ import { AbortError } from '@shopify/cli-kit/node/error';
9
10
 
10
11
  class SetupCSS extends Command {
12
+ static descriptionWithMarkdown = "Adds support for certain CSS strategies to your project.";
11
13
  static description = "Setup CSS strategies for your project.";
12
14
  static flags = {
13
15
  ...commonFlags.path,
@@ -37,6 +39,11 @@ async function runSetupCSS({
37
39
  force = false,
38
40
  installDeps = true
39
41
  }) {
42
+ if (!await hasRemixConfigFile(directory)) {
43
+ throw new AbortError(
44
+ "No remix.config.js file found. This command is not supported in Vite projects."
45
+ );
46
+ }
40
47
  const remixConfigPromise = getRemixConfig(directory);
41
48
  const strategy = flagStrategy ? flagStrategy : await renderCssPrompt();
42
49
  const remixConfig = await remixConfigPromise;
@@ -7,6 +7,7 @@ import { getRemixConfig } from '../../../lib/remix-config.js';
7
7
  import { SETUP_I18N_STRATEGIES, renderI18nPrompt, setupI18nStrategy, I18N_STRATEGY_NAME_MAP } from '../../../lib/setups/i18n/index.js';
8
8
 
9
9
  class SetupMarkets extends Command {
10
+ static descriptionWithMarkdown = "Adds support for multiple [markets](https://shopify.dev/docs/custom-storefronts/hydrogen/markets) to your project by using the URL structure.";
10
11
  static description = "Setup support for multiple markets in your project.";
11
12
  static flags = {
12
13
  ...commonFlags.path