@shopify/cli-hydrogen 5.1.1 → 5.1.2

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.
@@ -42,12 +42,12 @@ class Build extends Command {
42
42
  await runBuild({
43
43
  ...flagsToCamelObject(flags),
44
44
  useCodegen: flags["codegen-unstable"],
45
- path: directory
45
+ directory
46
46
  });
47
47
  }
48
48
  }
49
49
  async function runBuild({
50
- path: appPath,
50
+ directory,
51
51
  useCodegen = false,
52
52
  codegenConfigPath,
53
53
  sourcemap = false,
@@ -56,7 +56,7 @@ async function runBuild({
56
56
  if (!process.env.NODE_ENV) {
57
57
  process.env.NODE_ENV = "production";
58
58
  }
59
- const { root, buildPath, buildPathClient, buildPathWorkerFile, publicPath } = getProjectPaths(appPath);
59
+ const { root, buildPath, buildPathClient, buildPathWorkerFile, publicPath } = getProjectPaths(directory);
60
60
  await Promise.all([checkLockfileStatus(root), muteRemixLogs()]);
61
61
  console.time(LOG_WORKER_BUILT);
62
62
  outputInfo(`
@@ -125,7 +125,9 @@ This build is missing ${missingRoutes.length} route${missingRoutes.length > 1 ?
125
125
  );
126
126
  }
127
127
  }
128
- process.exit(0);
128
+ if (!process.env.SHOPIFY_UNIT_TEST) {
129
+ process.exit(0);
130
+ }
129
131
  }
130
132
  async function copyPublicFiles(publicPath, buildPathClient) {
131
133
  return copyFile(publicPath, buildPathClient);
@@ -33,4 +33,4 @@ async function runCheckRoutes({ directory }) {
33
33
  logMissingRoutes(findMissingRoutes(remixConfig));
34
34
  }
35
35
 
36
- export { GenerateRoute as default };
36
+ export { GenerateRoute as default, runCheckRoutes };
@@ -29,17 +29,17 @@ class Codegen extends Command {
29
29
  const directory = flags.path ? path.resolve(flags.path) : process.cwd();
30
30
  await runCodegen({
31
31
  ...flagsToCamelObject(flags),
32
- path: directory
32
+ directory
33
33
  });
34
34
  }
35
35
  }
36
36
  async function runCodegen({
37
- path: appPath,
37
+ directory,
38
38
  codegenConfigPath,
39
39
  forceSfapiVersion,
40
40
  watch
41
41
  }) {
42
- const { root } = getProjectPaths(appPath);
42
+ const { root } = getProjectPaths(directory);
43
43
  const remixConfig = await getRemixConfig(root);
44
44
  console.log("");
45
45
  const generatedFiles = await codegen({
@@ -1,39 +1,30 @@
1
1
  import { fileURLToPath } from 'node:url';
2
2
  import { vi, describe, beforeEach, it, expect } from 'vitest';
3
- import { temporaryDirectoryTask } from 'tempy';
4
3
  import { runInit } from './init.js';
5
4
  import { exec } from '@shopify/cli-kit/node/system';
6
5
  import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
7
- import { readFile, writeFile, isDirectory } from '@shopify/cli-kit/node/fs';
8
- import { basename, joinPath } from '@shopify/cli-kit/node/path';
6
+ import { writeFile, inTemporaryDirectory, readFile, isDirectory, removeFile, fileExists } from '@shopify/cli-kit/node/fs';
7
+ import { joinPath, basename } from '@shopify/cli-kit/node/path';
9
8
  import { checkHydrogenVersion } from '../../lib/check-version.js';
10
9
  import { handleProjectLocation } from '../../lib/onboarding/common.js';
11
10
  import glob from 'fast-glob';
12
11
  import { getSkeletonSourceDir } from '../../lib/build.js';
13
12
  import { execAsync } from '../../lib/process.js';
14
13
  import { rmdir, symlink } from 'fs-extra';
14
+ import { runCheckRoutes } from './check.js';
15
+ import { runCodegen } from './codegen-unstable.js';
16
+ import { runBuild } from './build.js';
15
17
 
18
+ const { renderTasksHook } = vi.hoisted(() => ({ renderTasksHook: vi.fn() }));
19
+ vi.mock("../../lib/check-version.js");
16
20
  vi.mock("../../lib/template-downloader.js", async () => ({
17
- getLatestTemplates: () => Promise.resolve({})
21
+ getLatestTemplates: () => Promise.resolve({
22
+ version: "",
23
+ templatesDir: fileURLToPath(
24
+ new URL("../../../../../templates", import.meta.url)
25
+ )
26
+ })
18
27
  }));
19
- vi.mock(
20
- "@shopify/cli-kit/node/node-package-manager",
21
- async (importOriginal) => {
22
- const original = await importOriginal();
23
- return {
24
- ...original,
25
- installNodeModules: vi.fn(),
26
- getPackageManager: () => Promise.resolve("npm"),
27
- packageManagerUsedForCreating: () => Promise.resolve("npm")
28
- };
29
- }
30
- );
31
- vi.mock("../../lib/check-version.js");
32
- const { renderTasksHook } = vi.hoisted(() => {
33
- return {
34
- renderTasksHook: vi.fn()
35
- };
36
- });
37
28
  vi.mock("@shopify/cli-kit/node/ui", async () => {
38
29
  const original = await vi.importActual("@shopify/cli-kit/node/ui");
39
30
  return {
@@ -48,6 +39,30 @@ vi.mock("@shopify/cli-kit/node/ui", async () => {
48
39
  })
49
40
  };
50
41
  });
42
+ vi.mock(
43
+ "@shopify/cli-kit/node/node-package-manager",
44
+ async (importOriginal) => {
45
+ const original = await importOriginal();
46
+ return {
47
+ ...original,
48
+ getPackageManager: () => Promise.resolve("npm"),
49
+ packageManagerUsedForCreating: () => Promise.resolve("npm"),
50
+ installNodeModules: vi.fn(async ({ directory }) => {
51
+ renderTasksHook.mockImplementationOnce(async () => {
52
+ await writeFile(`${directory}/package-lock.json`, "{}");
53
+ });
54
+ await rmdir(joinPath(directory, "node_modules")).catch(() => {
55
+ });
56
+ await symlink(
57
+ fileURLToPath(
58
+ new URL("../../../../../node_modules", import.meta.url)
59
+ ),
60
+ joinPath(directory, "node_modules")
61
+ );
62
+ })
63
+ };
64
+ }
65
+ );
51
66
  vi.mock("../../lib/onboarding/common.js", async (importOriginal) => {
52
67
  const original = await importOriginal();
53
68
  return Object.keys(original).reduce((acc, item) => {
@@ -65,10 +80,11 @@ describe("init", () => {
65
80
  const outputMock = mockAndCaptureOutput();
66
81
  beforeEach(() => {
67
82
  vi.clearAllMocks();
83
+ vi.unstubAllEnvs();
68
84
  outputMock.clear();
69
85
  });
70
86
  it("checks Hydrogen version", async () => {
71
- await temporaryDirectoryTask(async (tmpDir) => {
87
+ await inTemporaryDirectory(async (tmpDir) => {
72
88
  const showUpgradeMock = vi.fn((param) => ({
73
89
  currentVersion: "1.0.0",
74
90
  newVersion: "1.0.1"
@@ -83,9 +99,89 @@ describe("init", () => {
83
99
  );
84
100
  });
85
101
  });
102
+ describe("remote templates", () => {
103
+ it("throws for unknown templates", async () => {
104
+ await inTemporaryDirectory(async (tmpDir) => {
105
+ await expect(
106
+ runInit({
107
+ path: tmpDir,
108
+ git: false,
109
+ language: "ts",
110
+ template: "https://github.com/some/repo"
111
+ })
112
+ ).rejects.toThrow("supported");
113
+ });
114
+ });
115
+ it("creates basic projects", async () => {
116
+ await inTemporaryDirectory(async (tmpDir) => {
117
+ await runInit({
118
+ path: tmpDir,
119
+ git: false,
120
+ language: "ts",
121
+ template: "hello-world"
122
+ });
123
+ const helloWorldFiles = await glob("**/*", {
124
+ cwd: getSkeletonSourceDir().replace("skeleton", "hello-world"),
125
+ ignore: ["**/node_modules/**", "**/dist/**"]
126
+ });
127
+ const projectFiles = await glob("**/*", { cwd: tmpDir });
128
+ const nonAppFiles = helloWorldFiles.filter(
129
+ (item) => !item.startsWith("app/")
130
+ );
131
+ expect(projectFiles).toEqual(expect.arrayContaining(nonAppFiles));
132
+ expect(projectFiles).toContain("app/root.tsx");
133
+ expect(projectFiles).toContain("app/entry.client.tsx");
134
+ expect(projectFiles).toContain("app/entry.server.tsx");
135
+ expect(projectFiles).not.toContain("app/components/Layout.tsx");
136
+ expect(projectFiles).not.toContain("app/routes/_index.tsx");
137
+ await expect(readFile(`${tmpDir}/package.json`)).resolves.toMatch(
138
+ `"name": "hello-world"`
139
+ );
140
+ const output = outputMock.info();
141
+ expect(output).toMatch("success");
142
+ expect(output).not.toMatch("warning");
143
+ expect(output).not.toMatch("Routes");
144
+ expect(output).toMatch(/Language:\s*TypeScript/);
145
+ expect(output).toMatch("Help");
146
+ expect(output).toMatch("Next steps");
147
+ expect(output).toMatch(
148
+ /Run `cd .*? &&[^\w]*?npm[^\w]*?install[^\w]*?&&[^\w]*?npm[^\w]*?run[^\w]*?dev`/ims
149
+ );
150
+ });
151
+ });
152
+ it("transpiles projects to JS", async () => {
153
+ await inTemporaryDirectory(async (tmpDir) => {
154
+ await runInit({
155
+ path: tmpDir,
156
+ git: false,
157
+ language: "js",
158
+ template: "hello-world"
159
+ });
160
+ const helloWorldFiles = await glob("**/*", {
161
+ cwd: getSkeletonSourceDir().replace("skeleton", "hello-world"),
162
+ ignore: ["**/node_modules/**", "**/dist/**"]
163
+ });
164
+ const projectFiles = await glob("**/*", { cwd: tmpDir });
165
+ expect(projectFiles).toEqual(
166
+ expect.arrayContaining(
167
+ helloWorldFiles.filter((item) => !item.endsWith(".d.ts")).map(
168
+ (item) => item.replace(/\.ts(x)?$/, ".js$1").replace(/tsconfig\.json$/, "jsconfig.json")
169
+ )
170
+ )
171
+ );
172
+ await expect(readFile(`${tmpDir}/server.js`)).resolves.toMatch(
173
+ /export default {\n\s+async fetch\(\s*request,\s*env,\s*executionContext,?\s*\)/
174
+ );
175
+ const output = outputMock.info();
176
+ expect(output).toMatch("success");
177
+ expect(output).not.toMatch("warning");
178
+ expect(output).toMatch(/Language:\s*JavaScript/);
179
+ });
180
+ });
181
+ });
86
182
  describe("local templates", () => {
87
183
  it("creates basic projects", async () => {
88
- await temporaryDirectoryTask(async (tmpDir) => {
184
+ await inTemporaryDirectory(async (tmpDir) => {
89
185
  await runInit({
90
186
  path: tmpDir,
91
187
  git: false,
@@ -129,7 +225,7 @@ describe("init", () => {
129
225
  });
130
226
  });
131
227
  it("creates projects with route files", async () => {
132
- await temporaryDirectoryTask(async (tmpDir) => {
228
+ await inTemporaryDirectory(async (tmpDir) => {
133
229
  await runInit({ path: tmpDir, git: false, routes: true, language: "ts" });
134
230
  const skeletonFiles = await glob("**/*", {
135
231
  cwd: getSkeletonSourceDir(),
@@ -152,7 +248,7 @@ describe("init", () => {
152
248
  });
153
249
  });
154
250
  it("transpiles projects to JS", async () => {
155
- await temporaryDirectoryTask(async (tmpDir) => {
251
+ await inTemporaryDirectory(async (tmpDir) => {
156
252
  await runInit({ path: tmpDir, git: false, routes: true, language: "js" });
157
253
  const skeletonFiles = await glob("**/*", {
158
254
  cwd: getSkeletonSourceDir(),
@@ -182,7 +278,7 @@ describe("init", () => {
182
278
  });
183
279
  describe("styling libraries", () => {
184
280
  it("scaffolds Tailwind CSS", async () => {
185
- await temporaryDirectoryTask(async (tmpDir) => {
281
+ await inTemporaryDirectory(async (tmpDir) => {
186
282
  await runInit({
187
283
  path: tmpDir,
188
284
  git: false,
@@ -207,7 +303,7 @@ describe("init", () => {
207
303
  });
208
304
  });
209
305
  it("scaffolds CSS Modules", async () => {
210
- await temporaryDirectoryTask(async (tmpDir) => {
306
+ await inTemporaryDirectory(async (tmpDir) => {
211
307
  await runInit({
212
308
  path: tmpDir,
213
309
  git: false,
@@ -229,7 +325,7 @@ describe("init", () => {
229
325
  });
230
326
  });
231
327
  it("scaffolds Vanilla Extract", async () => {
232
- await temporaryDirectoryTask(async (tmpDir) => {
328
+ await inTemporaryDirectory(async (tmpDir) => {
233
329
  await runInit({
234
330
  path: tmpDir,
235
331
  git: false,
@@ -253,7 +349,7 @@ describe("init", () => {
253
349
  });
254
350
  describe("i18n strategies", () => {
255
351
  it("scaffolds i18n with domains strategy", async () => {
256
- await temporaryDirectoryTask(async (tmpDir) => {
352
+ await inTemporaryDirectory(async (tmpDir) => {
257
353
  await runInit({
258
354
  path: tmpDir,
259
355
  git: false,
@@ -273,7 +369,7 @@ describe("init", () => {
273
369
  });
274
370
  });
275
371
  it("scaffolds i18n with subdomains strategy", async () => {
276
- await temporaryDirectoryTask(async (tmpDir) => {
372
+ await inTemporaryDirectory(async (tmpDir) => {
277
373
  await runInit({
278
374
  path: tmpDir,
279
375
  git: false,
@@ -293,7 +389,7 @@ describe("init", () => {
293
389
  });
294
390
  });
295
391
  it("scaffolds i18n with subfolders strategy", async () => {
296
- await temporaryDirectoryTask(async (tmpDir) => {
392
+ await inTemporaryDirectory(async (tmpDir) => {
297
393
  await runInit({
298
394
  path: tmpDir,
299
395
  git: false,
@@ -315,10 +411,7 @@ describe("init", () => {
315
411
  });
316
412
  describe("git", () => {
317
413
  it("initializes a git repository and creates initial commits", async () => {
318
- await temporaryDirectoryTask(async (tmpDir) => {
319
- renderTasksHook.mockImplementationOnce(async () => {
320
- await writeFile(`${tmpDir}/package-lock.json`, "{}");
321
- });
414
+ await inTemporaryDirectory(async (tmpDir) => {
322
415
  await runInit({
323
416
  path: tmpDir,
324
417
  git: true,
@@ -345,10 +438,7 @@ describe("init", () => {
345
438
  });
346
439
  describe("project validity", () => {
347
440
  it("typechecks the project", async () => {
348
- await temporaryDirectoryTask(async (tmpDir) => {
349
- renderTasksHook.mockImplementationOnce(async () => {
350
- await writeFile(`${tmpDir}/package-lock.json`, "{}");
351
- });
441
+ await inTemporaryDirectory(async (tmpDir) => {
352
442
  await runInit({
353
443
  path: tmpDir,
354
444
  git: true,
@@ -358,21 +448,77 @@ describe("init", () => {
358
448
  routes: true,
359
449
  installDeps: true
360
450
  });
361
- await rmdir(joinPath(tmpDir, "node_modules")).catch(() => {
362
- });
363
- await symlink(
364
- fileURLToPath(
365
- new URL("../../../../../node_modules", import.meta.url)
366
- ),
367
- joinPath(tmpDir, "node_modules")
368
- );
369
451
  await expect(
370
- exec("npm", ["run", "typecheck"], {
371
- cwd: tmpDir
372
- })
452
+ exec("npm", ["run", "typecheck"], { cwd: tmpDir })
373
453
  ).resolves.not.toThrow();
374
454
  });
375
455
  });
456
+ it("contains all standard routes", async () => {
457
+ await inTemporaryDirectory(async (tmpDir) => {
458
+ await runInit({
459
+ path: tmpDir,
460
+ git: true,
461
+ language: "ts",
462
+ i18n: "subfolders",
463
+ routes: true,
464
+ installDeps: true
465
+ });
466
+ outputMock.clear();
467
+ await runCheckRoutes({ directory: tmpDir });
468
+ const output = outputMock.info();
469
+ expect(output).toMatch("success");
470
+ });
471
+ });
472
+ it("supports codegen", async () => {
473
+ await inTemporaryDirectory(async (tmpDir) => {
474
+ await runInit({
475
+ path: tmpDir,
476
+ git: true,
477
+ language: "ts",
478
+ routes: true,
479
+ installDeps: true
480
+ });
481
+ outputMock.clear();
482
+ const codegenFile = `${tmpDir}/storefrontapi.generated.d.ts`;
483
+ const codegenFromTemplate = await readFile(codegenFile);
484
+ expect(codegenFromTemplate).toBeTruthy();
485
+ await removeFile(codegenFile);
486
+ expect(fileExists(codegenFile)).resolves.toBeFalsy();
487
+ await expect(runCodegen({ directory: tmpDir })).resolves.not.toThrow();
488
+ const output = outputMock.info();
489
+ expect(output).toMatch("success");
490
+ await expect(readFile(codegenFile)).resolves.toEqual(
491
+ codegenFromTemplate
492
+ );
493
+ });
494
+ });
495
+ it("builds the generated project", async () => {
496
+ await inTemporaryDirectory(async (tmpDir) => {
497
+ await runInit({
498
+ path: tmpDir,
499
+ git: true,
500
+ language: "ts",
501
+ styling: "postcss",
502
+ i18n: "subfolders",
503
+ routes: true,
504
+ installDeps: true
505
+ });
506
+ outputMock.clear();
507
+ vi.stubEnv("NODE_ENV", "production");
508
+ await expect(runBuild({ directory: tmpDir })).resolves.not.toThrow();
509
+ const expectedBundlePath = "dist/worker/index.js";
510
+ const output = outputMock.output();
511
+ expect(output).toMatch(expectedBundlePath);
512
+ expect(
513
+ fileExists(joinPath(tmpDir, expectedBundlePath))
514
+ ).resolves.toBeTruthy();
515
+ const mb = Number(
516
+ output.match(/index\.js\s+([\d.]+)\s+MB/)?.[1] || ""
517
+ );
518
+ expect(mb).toBeGreaterThan(0);
519
+ expect(mb).toBeLessThan(1);
520
+ });
521
+ });
376
522
  });
377
523
  });
378
524
  });
@@ -44,7 +44,7 @@ async function runSetup(options) {
44
44
  }
45
45
  }
46
46
  ];
47
- const i18nStrategy = options.i18n ? options.i18n : await renderI18nPrompt({
47
+ const i18nStrategy = options.markets ? options.markets : await renderI18nPrompt({
48
48
  abortSignal: controller.signal,
49
49
  extraChoices: { none: "Set up later" }
50
50
  });
@@ -130,4 +130,4 @@ async function runSetup(options) {
130
130
  );
131
131
  }
132
132
 
133
- export { Setup as default };
133
+ export { Setup as default, runSetup };
@@ -0,0 +1,62 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { vi, describe, beforeEach, it, expect } from 'vitest';
3
+ import { inTemporaryDirectory, copyFile, fileExists, readFile } from '@shopify/cli-kit/node/fs';
4
+ import { joinPath } from '@shopify/cli-kit/node/path';
5
+ import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
6
+ import { runSetup } from './setup.js';
7
+ import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
8
+
9
+ vi.mock("../../lib/shell.js");
10
+ vi.mock("@shopify/cli-kit/node/ui", async () => {
11
+ const original = await vi.importActual("@shopify/cli-kit/node/ui");
12
+ return {
13
+ ...original,
14
+ renderConfirmationPrompt: vi.fn(),
15
+ renderSelectPrompt: vi.fn(),
16
+ renderTextPrompt: vi.fn(),
17
+ renderInfo: vi.fn()
18
+ };
19
+ });
20
+ describe("setup", () => {
21
+ const outputMock = mockAndCaptureOutput();
22
+ beforeEach(() => {
23
+ vi.resetAllMocks();
24
+ });
25
+ beforeEach(() => {
26
+ outputMock.clear();
27
+ });
28
+ it("sets up an i18n strategy and generates routes", async () => {
29
+ await inTemporaryDirectory(async (tmpDir) => {
30
+ await copyFile(
31
+ fileURLToPath(
32
+ new URL("../../../../../templates/hello-world", import.meta.url)
33
+ ),
34
+ tmpDir
35
+ );
36
+ await expect(
37
+ fileExists(joinPath(tmpDir, "app/routes/_index.tsx"))
38
+ ).resolves.toBeFalsy();
39
+ vi.mocked(renderConfirmationPrompt).mockResolvedValueOnce(true);
40
+ await expect(
41
+ runSetup({
42
+ directory: tmpDir,
43
+ markets: "subfolders",
44
+ installDeps: false
45
+ })
46
+ ).resolves.not.toThrow();
47
+ await expect(
48
+ fileExists(joinPath(tmpDir, "app/routes/($locale)._index.tsx"))
49
+ ).resolves.toBeTruthy();
50
+ const serverFile = await readFile(`${tmpDir}/server.ts`);
51
+ expect(serverFile).toMatch(/i18n: getLocaleFromRequest\(request\),/);
52
+ expect(serverFile).toMatch(/url.pathname/);
53
+ const output = outputMock.info();
54
+ expect(output).toMatch("success");
55
+ expect(output).not.toMatch("warning");
56
+ expect(output).toMatch(/Markets:\s*Subfolders/);
57
+ expect(output).toMatch("Routes");
58
+ expect(output).toMatch("Home (/ & /:catchAll)");
59
+ expect(output).toMatch("Account (/account/*)");
60
+ });
61
+ });
62
+ });
@@ -15,9 +15,9 @@
15
15
  "dependencies": {
16
16
  "@remix-run/react": "1.19.1",
17
17
  "@shopify/cli": "3.48.0",
18
- "@shopify/cli-hydrogen": "^5.1.1",
19
- "@shopify/hydrogen": "^2023.7.1",
20
- "@shopify/remix-oxygen": "^1.1.2",
18
+ "@shopify/cli-hydrogen": "^5.1.2",
19
+ "@shopify/hydrogen": "^2023.7.2",
20
+ "@shopify/remix-oxygen": "^1.1.3",
21
21
  "graphql": "^16.6.0",
22
22
  "graphql-tag": "^2.12.6",
23
23
  "isbot": "^3.6.6",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "devDependencies": {
28
28
  "@remix-run/dev": "1.19.1",
29
- "@shopify/oxygen-workers-types": "^3.17.2",
29
+ "@shopify/oxygen-workers-types": "^3.17.3",
30
30
  "@shopify/prettier-config": "^1.1.2",
31
31
  "@total-typescript/ts-reset": "^0.4.2",
32
32
  "@types/eslint": "^8.4.10",
@@ -1,13 +1,12 @@
1
- import { temporaryDirectoryTask } from 'tempy';
2
1
  import { describe, it, expect } from 'vitest';
3
2
  import { replaceFileContent, findFileWithExtension } from './file.js';
4
3
  import { resolvePath } from '@shopify/cli-kit/node/path';
5
- import { writeFile, readFile, mkdir } from '@shopify/cli-kit/node/fs';
4
+ import { inTemporaryDirectory, writeFile, readFile, mkdir } from '@shopify/cli-kit/node/fs';
6
5
 
7
6
  describe("File utils", () => {
8
7
  describe("replaceFileContent", () => {
9
8
  it("replaces the content of a file and formats it", async () => {
10
- await temporaryDirectoryTask(async (tmpDir) => {
9
+ await inTemporaryDirectory(async (tmpDir) => {
11
10
  const filepath = resolvePath(tmpDir, "index.js");
12
11
  await writeFile(
13
12
  filepath,
@@ -24,7 +23,7 @@ describe("File utils", () => {
24
23
  });
25
24
  describe("findFileWithExtension", () => {
26
25
  it("ignores missing files", async () => {
27
- await temporaryDirectoryTask(async (tmpDir) => {
26
+ await inTemporaryDirectory(async (tmpDir) => {
28
27
  expect(findFileWithExtension(tmpDir, "nope")).resolves.toEqual({
29
28
  filepath: void 0,
30
29
  extension: void 0,
@@ -33,7 +32,7 @@ describe("File utils", () => {
33
32
  });
34
33
  });
35
34
  it("finds the file with its corresponding extension and astType", async () => {
36
- await temporaryDirectoryTask(async (tmpDir) => {
35
+ await inTemporaryDirectory(async (tmpDir) => {
37
36
  await writeFile(resolvePath(tmpDir, "first.js"), "content");
38
37
  await writeFile(resolvePath(tmpDir, "second.tsx"), "content");
39
38
  await writeFile(resolvePath(tmpDir, "third.mjs"), "content");
@@ -3,7 +3,7 @@ import { copyFile } from '@shopify/cli-kit/node/fs';
3
3
  import { joinPath } from '@shopify/cli-kit/node/path';
4
4
  import { renderTasks, renderInfo } from '@shopify/cli-kit/node/ui';
5
5
  import { getLatestTemplates } from '../template-downloader.js';
6
- import { handleProjectLocation, createAbortHandler, handleLanguage, createInitialCommit, handleDependencies, renderProjectReady } from './common.js';
6
+ import { handleProjectLocation, createAbortHandler, handleLanguage, createInitialCommit, handleDependencies, commitAll, renderProjectReady } from './common.js';
7
7
 
8
8
  async function setupRemoteTemplate(options, controller) {
9
9
  const isOfficialTemplate = options.template === "demo-store" || options.template === "hello-world";
@@ -33,7 +33,9 @@ async function setupRemoteTemplate(options, controller) {
33
33
  controller,
34
34
  options.language
35
35
  );
36
- backgroundWorkPromise = backgroundWorkPromise.then(() => transpileProject().catch(abort)).then(() => createInitialCommit(project.directory));
36
+ backgroundWorkPromise = backgroundWorkPromise.then(() => transpileProject().catch(abort)).then(
37
+ () => options.git ? createInitialCommit(project.directory) : void 0
38
+ );
37
39
  const { packageManager, shouldInstallDeps, installDeps } = await handleDependencies(
38
40
  project.directory,
39
41
  controller,
@@ -73,10 +75,13 @@ async function setupRemoteTemplate(options, controller) {
73
75
  });
74
76
  }
75
77
  await renderTasks(tasks);
78
+ if (options.git) {
79
+ await commitAll(project.directory, "Lockfile");
80
+ }
76
81
  await renderProjectReady(project, setupSummary);
77
82
  if (isOfficialTemplate) {
78
83
  renderInfo({
79
- headline: `Your project will display inventory from the Hydrogen Demo Store.`,
84
+ headline: `Your project will display inventory from ${options.template === "demo-store" ? "the Hydrogen Demo Store" : "Mock.shop"}.`,
80
85
  body: `To connect this project to your Shopify store\u2019s inventory, update \`${project.name}/.env\` with your store ID and Storefront API key.`
81
86
  });
82
87
  }
@@ -1,8 +1,7 @@
1
1
  import { describe, beforeEach, vi, it, expect } from 'vitest';
2
- import { temporaryDirectoryTask } from 'tempy';
3
2
  import { getResolvedRoutes, generateRoutes, generateProjectFile } from './generate.js';
4
3
  import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
5
- import { fileExists, readFile, mkdir, writeFile } from '@shopify/cli-kit/node/fs';
4
+ import { inTemporaryDirectory, fileExists, readFile, mkdir, writeFile } from '@shopify/cli-kit/node/fs';
6
5
  import { joinPath, dirname } from '@shopify/cli-kit/node/path';
7
6
  import { getTemplateAppFile } from '../../../lib/build.js';
8
7
  import { getRemixConfig } from '../../remix-config.js';
@@ -21,7 +20,7 @@ describe("generate/route", () => {
21
20
  expect(
22
21
  resolvedRouteFiles.find((item) => /account_?\.login/.test(item))
23
22
  ).toBeTruthy();
24
- await temporaryDirectoryTask(async (tmpDir) => {
23
+ await inTemporaryDirectory(async (tmpDir) => {
25
24
  const directories = await createHydrogenFixture(tmpDir, {
26
25
  files: [
27
26
  ["jsconfig.json", JSON.stringify({ compilerOptions: { test: "js" } })],
@@ -51,7 +50,7 @@ describe("generate/route", () => {
51
50
  });
52
51
  });
53
52
  it("figures out the locale if a home route already exists", async () => {
54
- await temporaryDirectoryTask(async (tmpDir) => {
53
+ await inTemporaryDirectory(async (tmpDir) => {
55
54
  const route = "routes/pages.$handle";
56
55
  const directories = await createHydrogenFixture(tmpDir, {
57
56
  files: [
@@ -89,7 +88,7 @@ describe("generate/route", () => {
89
88
  });
90
89
  describe("generateProjectFile", () => {
91
90
  it("generates a route file for Remix v1", async () => {
92
- await temporaryDirectoryTask(async (tmpDir) => {
91
+ await inTemporaryDirectory(async (tmpDir) => {
93
92
  const route = "routes/pages.$handle";
94
93
  const directories = await createHydrogenFixture(tmpDir, {
95
94
  files: [],
@@ -107,7 +106,7 @@ describe("generate/route", () => {
107
106
  });
108
107
  });
109
108
  it("generates a route file for Remix v2", async () => {
110
- await temporaryDirectoryTask(async (tmpDir) => {
109
+ await inTemporaryDirectory(async (tmpDir) => {
111
110
  const route = "routes/custom.path.$handle._index";
112
111
  const directories = await createHydrogenFixture(tmpDir, {
113
112
  files: [],
@@ -123,7 +122,7 @@ describe("generate/route", () => {
123
122
  });
124
123
  });
125
124
  it("generates route files with locale prefix", async () => {
126
- await temporaryDirectoryTask(async (tmpDir) => {
125
+ await inTemporaryDirectory(async (tmpDir) => {
127
126
  const routeCode = `const str = 'hello world'`;
128
127
  const directories = await createHydrogenFixture(tmpDir, {
129
128
  files: [],
@@ -174,7 +173,7 @@ describe("generate/route", () => {
174
173
  });
175
174
  });
176
175
  it("produces a typescript file when typescript argument is true", async () => {
177
- await temporaryDirectoryTask(async (tmpDir) => {
176
+ await inTemporaryDirectory(async (tmpDir) => {
178
177
  const route = "routes/pages.$handle";
179
178
  const directories = await createHydrogenFixture(tmpDir, {
180
179
  files: [],
@@ -191,7 +190,7 @@ describe("generate/route", () => {
191
190
  });
192
191
  });
193
192
  it("prompts the user if there the file already exists", async () => {
194
- await temporaryDirectoryTask(async (tmpDir) => {
193
+ await inTemporaryDirectory(async (tmpDir) => {
195
194
  vi.mocked(renderConfirmationPrompt).mockImplementationOnce(
196
195
  async () => true
197
196
  );
@@ -212,7 +211,7 @@ describe("generate/route", () => {
212
211
  });
213
212
  });
214
213
  it("does not prompt the user if the force property is true", async () => {
215
- await temporaryDirectoryTask(async (tmpDir) => {
214
+ await inTemporaryDirectory(async (tmpDir) => {
216
215
  vi.mocked(renderConfirmationPrompt).mockImplementationOnce(
217
216
  async () => true
218
217
  );
@@ -229,7 +228,7 @@ describe("generate/route", () => {
229
228
  });
230
229
  });
231
230
  it("generates all the route dependencies", async () => {
232
- await temporaryDirectoryTask(async (tmpDir) => {
231
+ await inTemporaryDirectory(async (tmpDir) => {
233
232
  const templates = [
234
233
  [
235
234
  "routes/pages.$pageHandle.tsx",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.1.1",
2
+ "version": "5.1.2",
3
3
  "commands": {
4
4
  "hydrogen:build": {
5
5
  "id": "hydrogen:build",
package/package.json CHANGED
@@ -4,12 +4,12 @@
4
4
  "access": "public",
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
- "version": "5.1.1",
7
+ "version": "5.1.2",
8
8
  "license": "MIT",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "build": "rm -rf dist && tsup --config ./tsup.config.ts && node scripts/build-check.mjs",
12
- "dev": "rm -rf dist && tsup --watch --config ./tsup.config.ts",
12
+ "dev": "tsup --watch --config ./tsup.config.ts",
13
13
  "typecheck": "tsc --noEmit",
14
14
  "generate:manifest": "node scripts/generate-manifest.mjs",
15
15
  "test": "cross-env SHOPIFY_UNIT_TEST=1 vitest run --test-timeout=15000",
@@ -22,14 +22,14 @@
22
22
  "@types/prettier": "^2.7.2",
23
23
  "@types/recursive-readdir": "^2.2.1",
24
24
  "@types/tar-fs": "^2.0.1",
25
- "tempy": "^3.0.0",
25
+ "@vitest/coverage-v8": "^0.33.0",
26
26
  "type-fest": "^3.6.0",
27
27
  "vitest": "^0.33.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@remix-run/react": "1.19.1",
31
- "@shopify/hydrogen-react": "^2023.7.0",
32
- "@shopify/remix-oxygen": "^1.1.2"
31
+ "@shopify/hydrogen-react": "^2023.7.1",
32
+ "@shopify/remix-oxygen": "^1.1.3"
33
33
  },
34
34
  "dependencies": {
35
35
  "@ast-grep/napi": "^0.5.3",