@shopify/cli-hydrogen 8.3.0 → 8.4.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 (67) hide show
  1. package/dist/assets/hydrogen/i18n/domains.ts +4 -11
  2. package/dist/assets/hydrogen/i18n/mock-i18n-types.ts +4 -2
  3. package/dist/assets/hydrogen/i18n/subdomains.ts +4 -11
  4. package/dist/assets/hydrogen/i18n/subfolders.ts +4 -11
  5. package/dist/assets/hydrogen/starter/CHANGELOG.md +165 -0
  6. package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +5 -2
  7. package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +2 -2
  8. package/dist/assets/hydrogen/starter/app/components/PageLayout.tsx +65 -19
  9. package/dist/assets/hydrogen/starter/app/components/PaginatedResourceSection.tsx +42 -0
  10. package/dist/assets/hydrogen/starter/app/components/SearchForm.tsx +68 -0
  11. package/dist/assets/hydrogen/starter/app/components/SearchFormPredictive.tsx +76 -0
  12. package/dist/assets/hydrogen/starter/app/components/SearchResults.tsx +164 -0
  13. package/dist/assets/hydrogen/starter/app/components/SearchResultsPredictive.tsx +322 -0
  14. package/dist/assets/hydrogen/starter/app/entry.client.tsx +10 -8
  15. package/dist/assets/hydrogen/starter/app/entry.server.tsx +1 -1
  16. package/dist/assets/hydrogen/starter/app/lib/context.ts +43 -0
  17. package/dist/assets/hydrogen/starter/app/lib/fragments.ts +53 -0
  18. package/dist/assets/hydrogen/starter/app/lib/search.ts +74 -24
  19. package/dist/assets/hydrogen/starter/app/root.tsx +4 -7
  20. package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +2 -3
  21. package/dist/assets/hydrogen/starter/app/routes/account.orders._index.tsx +5 -19
  22. package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +11 -24
  23. package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +14 -27
  24. package/dist/assets/hydrogen/starter/app/routes/collections.$handle.tsx +12 -30
  25. package/dist/assets/hydrogen/starter/app/routes/collections._index.tsx +13 -27
  26. package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +9 -31
  27. package/dist/assets/hydrogen/starter/app/routes/search.tsx +312 -73
  28. package/dist/assets/hydrogen/starter/app/styles/reset.css +12 -2
  29. package/dist/assets/hydrogen/starter/env.d.ts +11 -30
  30. package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.jpg +0 -0
  31. package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +391 -0
  32. package/dist/assets/hydrogen/starter/guides/search/search.jpg +0 -0
  33. package/dist/assets/hydrogen/starter/guides/search/search.md +333 -0
  34. package/dist/assets/hydrogen/starter/package.json +4 -4
  35. package/dist/assets/hydrogen/starter/server.ts +18 -74
  36. package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +242 -172
  37. package/dist/assets/hydrogen/virtual-routes/components/{PageLayout.jsx → Layout.jsx} +2 -2
  38. package/dist/assets/hydrogen/virtual-routes/virtual-root.jsx +7 -6
  39. package/dist/commands/hydrogen/build.js +4 -2
  40. package/dist/commands/hydrogen/codegen.js +11 -3
  41. package/dist/commands/hydrogen/debug/cpu.js +2 -3
  42. package/dist/commands/hydrogen/deploy.js +8 -6
  43. package/dist/commands/hydrogen/dev.js +13 -11
  44. package/dist/commands/hydrogen/env/pull.js +5 -3
  45. package/dist/commands/hydrogen/env/push.js +2 -5
  46. package/dist/commands/hydrogen/preview.js +11 -7
  47. package/dist/commands/hydrogen/setup.js +2 -4
  48. package/dist/index.d.ts +5 -1
  49. package/dist/lib/classic-compiler/dev.js +8 -4
  50. package/dist/lib/codegen.js +1 -0
  51. package/dist/lib/dev-shared.js +17 -15
  52. package/dist/lib/environment-variables.js +5 -4
  53. package/dist/lib/flags.js +7 -0
  54. package/dist/lib/log.js +1 -7
  55. package/dist/lib/onboarding/local.js +22 -7
  56. package/dist/lib/remix-config.js +8 -3
  57. package/dist/lib/setups/css/replacers.js +2 -2
  58. package/dist/lib/setups/i18n/index.js +3 -6
  59. package/dist/lib/setups/i18n/replacers.js +62 -134
  60. package/dist/lib/template-diff.js +15 -0
  61. package/dist/lib/transpile/morph/functions.js +3 -2
  62. package/dist/lib/transpile/morph/typedefs.js +4 -1
  63. package/dist/lib/vite-config.js +13 -1
  64. package/oclif.manifest.json +39 -2
  65. package/package.json +3 -3
  66. package/dist/assets/hydrogen/starter/app/components/Search.tsx +0 -514
  67. package/dist/assets/hydrogen/starter/app/routes/api.predictive-search.tsx +0 -318
@@ -47,7 +47,7 @@ async function setupLocalStarterTemplate(options, controller) {
47
47
  {
48
48
  force: true,
49
49
  recursive: true,
50
- filter: (filepath) => !/^(app\/|dist\/|node_modules\/|server\.ts)/i.test(
50
+ filter: (filepath) => !/^(app\/|dist\/|node_modules\/|server\.ts|\.shopify\/)/i.test(
51
51
  relativePath(templateDir, filepath)
52
52
  )
53
53
  }
@@ -87,14 +87,16 @@ async function setupLocalStarterTemplate(options, controller) {
87
87
  # or \`${cliCommand} env pull\` to populate this file.`;
88
88
  backgroundWorkPromise = backgroundWorkPromise.then(() => {
89
89
  const promises = [
90
- // Add project name to package.json
91
90
  replaceFileContent(
92
91
  joinPath(project.directory, "package.json"),
93
92
  false,
94
- (content) => content.replace(
95
- /"name": "[^"]+"/,
96
- `"name": "${hyphenate(storefrontInfo?.title ?? project.name)}"`
97
- )
93
+ (content) => {
94
+ content = maybeInjectCliHydrogen(content);
95
+ return content.replace(
96
+ /"name": "[^"]+"/,
97
+ `"name": "${hyphenate(storefrontInfo?.title ?? project.name)}"`
98
+ );
99
+ }
98
100
  )
99
101
  ];
100
102
  let storefrontToLink;
@@ -223,7 +225,7 @@ async function setupLocalStarterTemplate(options, controller) {
223
225
  backgroundWorkPromise = backgroundWorkPromise.then(async () => {
224
226
  await setupI18n({
225
227
  rootDirectory: project.directory,
226
- serverEntryPoint: language === "ts" ? "server.ts" : "server.js"
228
+ contextCreate: language === "ts" ? "app/lib/context.ts" : "app/lib/context.js"
227
229
  }).then(
228
230
  () => options.git ? commitAll(
229
231
  project.directory,
@@ -260,5 +262,18 @@ async function setupLocalStarterTemplate(options, controller) {
260
262
  ...setupSummary
261
263
  };
262
264
  }
265
+ function maybeInjectCliHydrogen(pkgJsonContent) {
266
+ const hydrogenDep = pkgJsonContent.match(
267
+ /^\s+"@shopify\/hydrogen":\s+"[^"]+",\n/m
268
+ )?.[0];
269
+ if (hydrogenDep && /"0\.0\.0-\w+-/.test(hydrogenDep)) {
270
+ const cliHydrogenDep = hydrogenDep.replace("hydrogen", "cli-hydrogen");
271
+ pkgJsonContent = pkgJsonContent.replace(
272
+ hydrogenDep,
273
+ cliHydrogenDep + hydrogenDep
274
+ );
275
+ }
276
+ return pkgJsonContent;
277
+ }
263
278
 
264
279
  export { setupLocalStarterTemplate };
@@ -7,7 +7,7 @@ import { fileExists } from '@shopify/cli-kit/node/fs';
7
7
  import { muteRemixLogs } from './log.js';
8
8
  import { REQUIRED_REMIX_VERSION } from './remix-version-check.js';
9
9
  import { findFileWithExtension } from './file.js';
10
- import { getViteConfig } from './vite-config.js';
10
+ import { isViteProject, getViteConfig } from './vite-config.js';
11
11
  import { importLocal } from './import-utils.js';
12
12
  import { isHydrogenMonorepo, hydrogenPackagesPath } from './build.js';
13
13
 
@@ -15,6 +15,11 @@ async function hasRemixConfigFile(root) {
15
15
  const result = await findFileWithExtension(root, "remix.config");
16
16
  return !!result.filepath;
17
17
  }
18
+ async function isClassicProject(root) {
19
+ const isVite = await isViteProject(root);
20
+ if (isVite) return false;
21
+ return hasRemixConfigFile(root);
22
+ }
18
23
  const BUILD_DIR = "dist";
19
24
  const CLIENT_SUBDIR = "client";
20
25
  const WORKER_SUBDIR = "worker";
@@ -47,7 +52,7 @@ function getRawRemixConfig(root) {
47
52
  });
48
53
  }
49
54
  async function getRemixConfig(root, mode = process.env.NODE_ENV) {
50
- if (!await hasRemixConfigFile(root)) {
55
+ if (await isViteProject(root)) {
51
56
  return (await getViteConfig(root)).remixConfig;
52
57
  }
53
58
  await muteRemixLogs(root);
@@ -160,4 +165,4 @@ async function assertEntryFileExists(root, fileRelative) {
160
165
  }
161
166
  }
162
167
 
163
- export { assertOxygenChecks, getProjectPaths, getRawRemixConfig, getRemixConfig, handleRemixImportFail, hasRemixConfigFile };
168
+ export { assertOxygenChecks, getProjectPaths, getRawRemixConfig, getRemixConfig, handleRemixImportFail, hasRemixConfigFile, isClassicProject };
@@ -14,8 +14,8 @@ async function replaceRootLinks(appDirectory, formatConfig, importer) {
14
14
  }
15
15
  const astGrep = await importLangAstGrep(astType);
16
16
  const root = astGrep.parse(content).root();
17
- const importNodes = root.findAll({ rule: { kind: "import_statement" } });
18
- const lastImportNode = importNodes.findLast((node) => node.text().includes(".css")) || importNodes.pop();
17
+ const importNodes = root.findAll({ rule: { kind: "import_statement" } }).reverse();
18
+ const lastImportNode = importNodes.find((node) => node.text().includes(".css")) || importNodes.shift();
19
19
  const linksReturnNode = root.find({
20
20
  utils: {
21
21
  "has-links-id": {
@@ -1,7 +1,7 @@
1
1
  import { renderSelectPrompt } from '@shopify/cli-kit/node/ui';
2
- import { fileExists, readFile } from '@shopify/cli-kit/node/fs';
2
+ import { fileExists } from '@shopify/cli-kit/node/fs';
3
3
  import { getCodeFormatOptions } from '../../format-code.js';
4
- import { replaceServerI18n, replaceRemixEnv } from './replacers.js';
4
+ import { replaceContextI18n } from './replacers.js';
5
5
  import { getAssetsDir } from '../../build.js';
6
6
 
7
7
  const SETUP_I18N_STRATEGIES = [
@@ -20,11 +20,8 @@ async function setupI18nStrategy(strategy, options) {
20
20
  if (!await fileExists(templatePath)) {
21
21
  throw new Error("Unknown strategy");
22
22
  }
23
- const template = await readFile(templatePath);
24
23
  const formatConfig = await getCodeFormatOptions(options.rootDirectory);
25
- const isJs = options.serverEntryPoint?.endsWith(".js") ?? false;
26
- await replaceServerI18n(options, formatConfig, template, isJs);
27
- await replaceRemixEnv(options, formatConfig, template);
24
+ await replaceContextI18n(options, formatConfig, templatePath);
28
25
  }
29
26
  async function renderI18nPrompt(options) {
30
27
  const i18nStrategies = Object.entries({
@@ -1,15 +1,25 @@
1
1
  import { AbortError } from '@shopify/cli-kit/node/error';
2
- import { joinPath, resolvePath } from '@shopify/cli-kit/node/path';
3
- import { fileExists } from '@shopify/cli-kit/node/fs';
2
+ import { joinPath, relativePath, extname, dirname, resolvePath } from '@shopify/cli-kit/node/path';
3
+ import { readFile, fileExists, copyFile } from '@shopify/cli-kit/node/fs';
4
4
  import { replaceFileContent, findFileWithExtension } from '../../file.js';
5
5
  import { importLangAstGrep } from '../../ast.js';
6
6
  import { transpileFile } from '../../transpile/index.js';
7
7
 
8
- async function replaceServerI18n({ rootDirectory, serverEntryPoint = "server" }, formatConfig, localeExtractImpl, isJs) {
9
- const { filepath, astType } = await findEntryFile({
8
+ async function replaceContextI18n({
9
+ rootDirectory,
10
+ contextCreate = joinPath("app", "lib", "context.ts")
11
+ }, formatConfig, i18nStrategyFilePath) {
12
+ const createContextMethodName = "createAppLoadContext";
13
+ const { filepath, astType } = await findContextCreateFile({
10
14
  rootDirectory,
11
- serverEntryPoint
15
+ contextCreate
12
16
  });
17
+ const localeExtractImpl = await readFile(i18nStrategyFilePath);
18
+ const i18nFileFinalPath = await replaceI18nStrategy(
19
+ { rootDirectory, contextCreate },
20
+ formatConfig,
21
+ i18nStrategyFilePath
22
+ );
13
23
  await replaceFileContent(filepath, formatConfig, async (content) => {
14
24
  const astGrep = await importLangAstGrep(astType);
15
25
  const root = astGrep.parse(content).root();
@@ -20,15 +30,11 @@ async function replaceServerI18n({ rootDirectory, serverEntryPoint = "server" },
20
30
  kind: "formal_parameters",
21
31
  stopBy: "end",
22
32
  inside: {
23
- kind: "method_definition",
33
+ kind: "function_declaration",
24
34
  stopBy: "end",
25
35
  has: {
26
- kind: "property_identifier",
27
- regex: "^fetch$"
28
- },
29
- inside: {
30
- kind: "export_statement",
31
- stopBy: "end"
36
+ kind: "identifier",
37
+ regex: `^${createContextMethodName}$`
32
38
  }
33
39
  }
34
40
  }
@@ -43,7 +49,7 @@ async function replaceServerI18n({ rootDirectory, serverEntryPoint = "server" },
43
49
  }
44
50
  const i18nFunctionCall = `${i18nFunctionName}(${requestIdentifierName})`;
45
51
  const hydrogenImportPath = "@shopify/hydrogen";
46
- const hydrogenImportName = "createStorefrontClient";
52
+ const hydrogenImportName = "createHydrogenContext";
47
53
  const importSpecifier = root.find({
48
54
  rule: {
49
55
  kind: "import_specifier",
@@ -67,7 +73,7 @@ async function replaceServerI18n({ rootDirectory, serverEntryPoint = "server" },
67
73
  importName = importAlias ?? importName;
68
74
  if (!importName) {
69
75
  throw new AbortError(
70
- `Could not find a Hydrogen import in ${serverEntryPoint}`,
76
+ `Could not find a Hydrogen import in ${contextCreate}`,
71
77
  `Please import "${hydrogenImportName}" from "${hydrogenImportPath}"`
72
78
  );
73
79
  }
@@ -88,40 +94,10 @@ async function replaceServerI18n({ rootDirectory, serverEntryPoint = "server" },
88
94
  });
89
95
  if (!argumentObject) {
90
96
  throw new AbortError(
91
- `Could not find a Hydrogen client instantiation with an inline object as argument in ${serverEntryPoint}`,
97
+ `Could not find a Hydrogen client instantiation with an inline object as argument in ${contextCreate}`,
92
98
  `Please add a call to ${importName}({...})`
93
99
  );
94
100
  }
95
- const defaultExportObject = root.find({
96
- rule: {
97
- kind: "export_statement",
98
- regex: "^export default \\{"
99
- }
100
- });
101
- if (!defaultExportObject) {
102
- throw new AbortError(
103
- "Could not find a default export in the server entry point"
104
- );
105
- }
106
- let localeExtractFn = localeExtractImpl.match(/^(\/\*\*.*?\*\/\n)?^function .+?^}/ms)?.[0] || "";
107
- if (!localeExtractFn) {
108
- throw new AbortError(
109
- "Could not find the locale extract function. This is a bug in Hydrogen."
110
- );
111
- }
112
- if (isJs) {
113
- localeExtractFn = await transpileFile(
114
- localeExtractFn,
115
- "locale-extract-server.ts"
116
- );
117
- } else {
118
- localeExtractFn = localeExtractFn.replace(/\/\*\*.*?\*\//gms, "");
119
- }
120
- const defaultExportEnd = defaultExportObject.range().end.index;
121
- content = content.slice(0, defaultExportEnd) + `
122
-
123
- ${localeExtractFn}
124
- ` + content.slice(defaultExportEnd);
125
101
  const i18nProperty = argumentObject.find({
126
102
  rule: {
127
103
  kind: "property_identifier",
@@ -143,109 +119,61 @@ ${localeExtractFn}
143
119
  const firstPart = content.slice(0, end.index - 1);
144
120
  content = firstPart + ((/,\s*$/.test(firstPart) ? "" : ",") + `i18n: ${i18nFunctionCall}`) + content.slice(end.index - 1);
145
121
  }
122
+ const lastImport = root.findAll({ rule: { kind: "import_statement" } }).pop();
123
+ const lastImportRange = lastImport?.range() ?? {
124
+ end: { index: 0 }
125
+ };
126
+ const i18nFunctionImport = joinPath(
127
+ "~",
128
+ relativePath(
129
+ joinPath(rootDirectory, "app"),
130
+ i18nFileFinalPath.slice(0, -extname(i18nFileFinalPath).length)
131
+ )
132
+ );
133
+ content = content.slice(0, lastImportRange.end.index) + `import {getLocaleFromRequest} from "${i18nFunctionImport}";` + content.slice(lastImportRange.end.index);
146
134
  return content;
147
135
  });
148
136
  }
149
- async function replaceRemixEnv({ rootDirectory }, formatConfig, localeExtractImpl) {
150
- let envPath = joinPath(rootDirectory, "env.d.ts");
151
- if (!await fileExists(envPath)) {
152
- envPath = "remix.env.d.ts";
153
- if (!await fileExists(envPath)) {
154
- return;
155
- }
156
- }
157
- const i18nType = localeExtractImpl.match(
158
- /^(export )?(type \w+ =\s+\{.*?\};)\n/ms
159
- )?.[2];
160
- const i18nTypeName = i18nType?.match(/^type (\w+)/)?.[1];
161
- if (!i18nTypeName) {
162
- return;
137
+ async function replaceI18nStrategy({
138
+ rootDirectory,
139
+ contextCreate = joinPath("app", "lib", "context.ts")
140
+ }, formatConfig, i18nStrategyFilePath) {
141
+ const isJs = contextCreate?.endsWith(".js") || false;
142
+ const i18nPath = joinPath(
143
+ rootDirectory,
144
+ dirname(contextCreate),
145
+ isJs ? "i18n.js" : "i18n.ts"
146
+ );
147
+ if (await fileExists(i18nPath)) {
148
+ throw new AbortError(
149
+ `${i18nPath} already exist. Renamed or remove the existing file before continue.`
150
+ );
163
151
  }
164
- await replaceFileContent(envPath, formatConfig, async (content) => {
165
- if (content.includes(`Storefront<`)) return;
166
- const astGrep = await importLangAstGrep("ts");
167
- const root = astGrep.parse(content).root();
168
- const storefrontTypeNode = root.find({
169
- rule: {
170
- kind: "property_signature",
171
- has: {
172
- kind: "type_annotation",
173
- has: {
174
- regex: "^Storefront$"
175
- }
176
- },
177
- inside: {
178
- kind: "interface_declaration",
179
- stopBy: "end",
180
- regex: "AppLoadContext"
181
- }
182
- }
183
- });
184
- if (storefrontTypeNode) {
185
- const storefrontTypeNodeRange = storefrontTypeNode.range();
186
- content = content.slice(0, storefrontTypeNodeRange.end.index) + `<${i18nTypeName}>` + content.slice(storefrontTypeNodeRange.end.index);
187
- }
188
- const ambientDeclarationContentNode = root.find({
189
- rule: {
190
- kind: "statement_block",
191
- inside: {
192
- kind: "ambient_declaration"
193
- }
194
- }
195
- });
196
- const i18nTypeDeclaration = `
197
- /**
198
- * The I18nLocale used for Storefront API query context.
199
- */
200
- ${i18nType}`;
201
- if (ambientDeclarationContentNode) {
202
- const { end } = ambientDeclarationContentNode.range();
203
- content = content.slice(0, end.index - 1) + `
204
-
205
- ${i18nTypeDeclaration}
206
- ` + content.slice(end.index - 1);
207
- } else {
208
- content = content + `
209
-
210
- declare global {
211
- ${i18nTypeDeclaration}
212
- }`;
213
- }
214
- const importImplTypes = localeExtractImpl.match(
215
- /import\s+type\s+[^;]+?;/
216
- )?.[0];
217
- if (importImplTypes) {
218
- const importPlace = root.findAll({
219
- rule: {
220
- kind: "import_statement",
221
- has: {
222
- kind: "string_fragment",
223
- stopBy: "end",
224
- regex: `^@shopify/hydrogen$`
225
- }
226
- }
227
- }).pop() ?? root.findAll({ rule: { kind: "import_statement" } }).pop() ?? root.findAll({ rule: { kind: "comment", regex: "^/// <reference" } }).pop();
228
- const importPlaceRange = importPlace?.range() ?? { end: { index: 0 } };
229
- content = content.slice(0, importPlaceRange.end.index) + importImplTypes.replace(
230
- /'[^']+'/,
231
- `'@shopify/hydrogen/storefront-api-types'`
232
- ) + content.slice(importPlaceRange.end.index);
152
+ await copyFile(i18nStrategyFilePath, i18nPath);
153
+ await replaceFileContent(i18nPath, formatConfig, async (content) => {
154
+ content = content.replace(/\.\/mock-i18n-types\.js/, "@shopify/hydrogen");
155
+ if (isJs) {
156
+ content = await transpileFile(content, i18nStrategyFilePath);
233
157
  }
234
158
  return content;
235
159
  });
160
+ return i18nPath;
236
161
  }
237
- async function findEntryFile({
162
+ async function findContextCreateFile({
238
163
  rootDirectory,
239
- serverEntryPoint = "server"
164
+ contextCreate = joinPath("app", "lib", "context.ts")
240
165
  }) {
241
- const match = serverEntryPoint.match(/\.([jt]sx?)$/)?.[1];
242
- const { filepath, astType } = match ? { filepath: resolvePath(rootDirectory, serverEntryPoint), astType: match } : await findFileWithExtension(rootDirectory, serverEntryPoint);
166
+ const match = contextCreate.match(/\.([jt]sx?)$/)?.[1];
167
+ const { filepath, astType } = match ? { filepath: resolvePath(rootDirectory, contextCreate), astType: match } : await findFileWithExtension(rootDirectory, joinPath(contextCreate));
243
168
  if (!filepath || !astType) {
244
169
  throw new AbortError(
245
- `Could not find a server entry point at ${serverEntryPoint}`
170
+ `Could not find a context create file at ${resolvePath(
171
+ rootDirectory,
172
+ contextCreate
173
+ )}`
246
174
  );
247
175
  }
248
176
  return { filepath, astType };
249
177
  }
250
178
 
251
- export { replaceRemixEnv, replaceServerI18n };
179
+ export { replaceContextI18n };
@@ -136,6 +136,21 @@ ${colors.dim(
136
136
  joinPath(diffDirectory, ".env")
137
137
  )
138
138
  ]);
139
+ },
140
+ /**
141
+ * Brings the generated d.ts files back to the original project.
142
+ */
143
+ copyDiffCodegen() {
144
+ return Promise.all([
145
+ copyFile(
146
+ joinPath(targetDirectory, "storefrontapi.generated.d.ts"),
147
+ joinPath(diffDirectory, "storefrontapi.generated.d.ts")
148
+ ),
149
+ copyFile(
150
+ joinPath(targetDirectory, "customer-accountapi.generated.d.ts"),
151
+ joinPath(diffDirectory, "customer-accountapi.generated.d.ts")
152
+ )
153
+ ]);
139
154
  }
140
155
  };
141
156
  }
@@ -21,9 +21,10 @@ function generateFunctionDocumentation(functionNode, variableStatement) {
21
21
  } else {
22
22
  const declaration = functionNode;
23
23
  const jsDocs = declaration.getJsDocs()[0];
24
- if (jsDocs?.getTags().length === 0) {
24
+ if (jsDocs && !jsDocs.getTags().find((tag) => tag.getTagName() === "return")) {
25
25
  const returnType = declaration.getReturnType().getText();
26
- if (isAnnotableType(returnType)) {
26
+ const hasManuallySpecifiedReturnType = !!declaration.getSignature().compilerSignature.getReturnType().aliasSymbol;
27
+ if (hasManuallySpecifiedReturnType) {
27
28
  jsDocs.addTag({ tagName: "return", text: normalizeType(returnType) });
28
29
  }
29
30
  }
@@ -28,7 +28,10 @@ function generateTypeDefs(sourceFile, code) {
28
28
  typedefs.push("");
29
29
  const knownGenerics = {
30
30
  MetaFunction: "T",
31
- SerializeFrom: "T"
31
+ SerializeFrom: "T",
32
+ Fetcher: "T",
33
+ PartialPredictiveSearchResult: "ItemType, ExtraProps",
34
+ PartialSearchResult: "ItemType"
32
35
  };
33
36
  typedefsFromImports.forEach((typeElements, moduleSpecifier) => {
34
37
  for (const typeElement of typeElements) {
@@ -1,11 +1,23 @@
1
1
  import { joinPath, resolvePath, dirname, basename } from '@shopify/cli-kit/node/path';
2
2
  import { findFileWithExtension } from './file.js';
3
3
  import { importVite } from './import-utils.js';
4
+ import { hasRemixConfigFile } from './remix-config.js';
5
+ import { renderWarning } from '@shopify/cli-kit/node/ui';
4
6
 
5
7
  async function hasViteConfig(root) {
6
8
  const result = await findFileWithExtension(root, "vite.config");
7
9
  return !!result.filepath;
8
10
  }
11
+ async function isViteProject(root) {
12
+ const isVite = await hasViteConfig(root);
13
+ if (isVite && await hasRemixConfigFile(root)) {
14
+ renderWarning({
15
+ headline: "Both Vite and Remix config files found.",
16
+ body: "The remix.config.js file is not used in Vite projects. Please remove it to avoid conflicts."
17
+ });
18
+ }
19
+ return isVite;
20
+ }
9
21
  async function getViteConfig(root, ssrEntryFlag) {
10
22
  const vite = await importVite(root);
11
23
  const command = "build";
@@ -73,4 +85,4 @@ function findOxygenPlugin(config) {
73
85
  return findPlugin(config, "oxygen:main");
74
86
  }
75
87
 
76
- export { findHydrogenPlugin, findOxygenPlugin, getViteConfig, hasViteConfig };
88
+ export { findHydrogenPlugin, findOxygenPlugin, getViteConfig, hasViteConfig, isViteProject };
@@ -174,6 +174,14 @@
174
174
  "required": false,
175
175
  "allowNo": false,
176
176
  "type": "boolean"
177
+ },
178
+ "diff": {
179
+ "description": "Applies the current files on top of Hydrogen's starter template in a temporary directory.",
180
+ "hidden": true,
181
+ "name": "diff",
182
+ "required": false,
183
+ "allowNo": false,
184
+ "type": "boolean"
177
185
  }
178
186
  },
179
187
  "hasDynamicHelp": false,
@@ -599,6 +607,15 @@
599
607
  "multiple": false,
600
608
  "type": "option"
601
609
  },
610
+ "env-file": {
611
+ "description": "Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`.",
612
+ "name": "env-file",
613
+ "required": false,
614
+ "default": ".env",
615
+ "hasDynamicHelp": false,
616
+ "multiple": false,
617
+ "type": "option"
618
+ },
602
619
  "disable-version-check": {
603
620
  "description": "Skip the version check when running `hydrogen dev`",
604
621
  "name": "disable-version-check",
@@ -741,6 +758,15 @@
741
758
  "multiple": false,
742
759
  "type": "option"
743
760
  },
761
+ "env-file": {
762
+ "description": "Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`.",
763
+ "name": "env-file",
764
+ "required": false,
765
+ "default": ".env",
766
+ "hasDynamicHelp": false,
767
+ "multiple": false,
768
+ "type": "option"
769
+ },
744
770
  "path": {
745
771
  "description": "The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run.",
746
772
  "env": "SHOPIFY_HYDROGEN_FLAG_PATH",
@@ -792,8 +818,10 @@
792
818
  "type": "option"
793
819
  },
794
820
  "env-file": {
795
- "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`.",
821
+ "description": "Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`.",
796
822
  "name": "env-file",
823
+ "required": false,
824
+ "default": ".env",
797
825
  "hasDynamicHelp": false,
798
826
  "multiple": false,
799
827
  "type": "option"
@@ -1322,6 +1350,15 @@
1322
1350
  "multiple": false,
1323
1351
  "type": "option"
1324
1352
  },
1353
+ "env-file": {
1354
+ "description": "Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`.",
1355
+ "name": "env-file",
1356
+ "required": false,
1357
+ "default": ".env",
1358
+ "hasDynamicHelp": false,
1359
+ "multiple": false,
1360
+ "type": "option"
1361
+ },
1325
1362
  "inspector-port": {
1326
1363
  "description": "The port where the inspector is available. Defaults to 9229.",
1327
1364
  "env": "SHOPIFY_HYDROGEN_FLAG_INSPECTOR_PORT",
@@ -1714,5 +1751,5 @@
1714
1751
  ]
1715
1752
  }
1716
1753
  },
1717
- "version": "8.3.0"
1754
+ "version": "8.4.0"
1718
1755
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
- "version": "8.3.0",
7
+ "version": "8.4.0",
8
8
  "license": "MIT",
9
9
  "type": "module",
10
10
  "scripts": {
@@ -34,9 +34,9 @@
34
34
  "dependencies": {
35
35
  "@ast-grep/napi": "0.11.0",
36
36
  "@oclif/core": "3.26.5",
37
- "@shopify/cli-kit": "3.64.0",
37
+ "@shopify/cli-kit": "3.65.1",
38
38
  "@shopify/oxygen-cli": "4.4.9",
39
- "@shopify/plugin-cloudflare": "3.64.0",
39
+ "@shopify/plugin-cloudflare": "3.65.1",
40
40
  "ansi-escapes": "^6.2.0",
41
41
  "chokidar": "3.5.3",
42
42
  "cli-truncate": "^4.0.0",