@shopify/cli-hydrogen 6.0.2 → 7.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.
- package/dist/commands/hydrogen/build.js +40 -78
- package/dist/commands/hydrogen/codegen.js +8 -3
- package/dist/commands/hydrogen/deploy.js +173 -37
- package/dist/commands/hydrogen/deploy.test.js +192 -20
- package/dist/commands/hydrogen/dev.js +56 -31
- package/dist/commands/hydrogen/init.js +1 -1
- package/dist/commands/hydrogen/init.test.js +155 -53
- package/dist/commands/hydrogen/link.js +5 -21
- package/dist/commands/hydrogen/link.test.js +10 -10
- package/dist/commands/hydrogen/preview.js +22 -11
- package/dist/commands/hydrogen/setup.js +0 -4
- package/dist/commands/hydrogen/setup.test.js +0 -1
- package/dist/commands/hydrogen/shortcut.js +1 -0
- package/dist/commands/hydrogen/upgrade.js +720 -0
- package/dist/commands/hydrogen/upgrade.test.js +786 -0
- package/dist/generator-templates/starter/.graphqlrc.yml +12 -1
- package/dist/generator-templates/starter/CHANGELOG.md +126 -0
- package/dist/generator-templates/starter/README.md +23 -0
- package/dist/generator-templates/starter/app/components/Cart.tsx +1 -1
- package/dist/generator-templates/starter/app/components/Footer.tsx +3 -1
- package/dist/generator-templates/starter/app/components/Header.tsx +5 -1
- package/dist/generator-templates/starter/app/components/Layout.tsx +14 -11
- package/dist/generator-templates/starter/app/components/Search.tsx +1 -1
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerAddressMutations.ts +61 -0
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +39 -0
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerOrderQuery.ts +87 -0
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +58 -0
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +24 -0
- package/dist/generator-templates/starter/app/lib/fragments.ts +102 -0
- package/dist/generator-templates/starter/app/lib/session.ts +67 -0
- package/dist/generator-templates/starter/app/root.tsx +11 -45
- package/dist/generator-templates/starter/app/routes/[robots.txt].tsx +0 -27
- package/dist/generator-templates/starter/app/routes/account.$.tsx +8 -4
- package/dist/generator-templates/starter/app/routes/account._index.tsx +5 -0
- package/dist/generator-templates/starter/app/routes/account.addresses.tsx +215 -206
- package/dist/generator-templates/starter/app/routes/account.orders.$id.tsx +56 -163
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +32 -109
- package/dist/generator-templates/starter/app/routes/account.profile.tsx +40 -180
- package/dist/generator-templates/starter/app/routes/account.tsx +20 -135
- package/dist/generator-templates/starter/app/routes/account_.authorize.tsx +5 -0
- package/dist/generator-templates/starter/app/routes/account_.login.tsx +3 -140
- package/dist/generator-templates/starter/app/routes/account_.logout.tsx +5 -24
- package/dist/generator-templates/starter/app/routes/cart.tsx +7 -5
- package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +2 -2
- package/dist/generator-templates/starter/app/routes/search.tsx +1 -1
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +506 -0
- package/dist/generator-templates/starter/package.json +11 -10
- package/dist/generator-templates/starter/remix.config.js +4 -0
- package/dist/generator-templates/starter/remix.env.d.ts +6 -11
- package/dist/generator-templates/starter/server.ts +24 -167
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +104 -881
- package/dist/hooks/init.js +4 -4
- package/dist/lib/auth.js +5 -10
- package/dist/lib/build.js +6 -1
- package/dist/lib/bundle/analyzer.js +36 -26
- package/dist/lib/check-lockfile.js +1 -0
- package/dist/lib/codegen.js +59 -18
- package/dist/lib/defer.js +12 -0
- package/dist/lib/file.js +52 -3
- package/dist/lib/flags.js +27 -9
- package/dist/lib/get-oxygen-deployment-data.test.js +4 -2
- package/dist/lib/graphql/admin/client.test.js +2 -2
- package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
- package/dist/lib/log.js +32 -14
- package/dist/lib/mini-oxygen/assets.js +118 -0
- package/dist/lib/mini-oxygen/common.js +2 -1
- package/dist/lib/mini-oxygen/index.js +7 -5
- package/dist/lib/mini-oxygen/mini-oxygen.test.js +214 -0
- package/dist/lib/mini-oxygen/node.js +19 -5
- package/dist/lib/mini-oxygen/workerd-inspector-logs.js +227 -0
- package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +200 -0
- package/dist/lib/mini-oxygen/workerd-inspector.js +62 -235
- package/dist/lib/mini-oxygen/workerd.js +74 -50
- package/dist/lib/missing-routes.js +6 -3
- package/dist/lib/onboarding/common.js +40 -9
- package/dist/lib/onboarding/local.js +19 -11
- package/dist/lib/onboarding/remote.js +48 -28
- package/dist/lib/render-errors.js +2 -0
- package/dist/lib/request-events.js +65 -31
- package/dist/lib/setups/css/assets.js +1 -46
- package/dist/lib/setups/css/css-modules.js +3 -2
- package/dist/lib/setups/css/postcss.js +4 -2
- package/dist/lib/setups/css/tailwind.js +4 -2
- package/dist/lib/setups/css/vanilla-extract.js +3 -2
- package/dist/lib/setups/i18n/replacers.test.js +56 -38
- package/dist/lib/shell.js +1 -1
- package/dist/lib/template-diff.js +89 -0
- package/dist/lib/template-downloader.js +3 -2
- package/dist/lib/transpile/project.js +1 -1
- package/dist/virtual-routes/assets/debug-network.css +592 -0
- package/dist/virtual-routes/assets/favicon-dark.svg +20 -0
- package/dist/virtual-routes/components/FlameChartWrapper.jsx +8 -10
- package/dist/virtual-routes/components/IconClose.jsx +38 -0
- package/dist/virtual-routes/components/IconDiscard.jsx +44 -0
- package/dist/virtual-routes/components/RequestDetails.jsx +179 -0
- package/dist/virtual-routes/components/RequestTable.jsx +92 -0
- package/dist/virtual-routes/components/RequestWaterfall.jsx +151 -0
- package/dist/virtual-routes/lib/useDebugNetworkServer.jsx +176 -0
- package/dist/virtual-routes/routes/subrequest-profiler.jsx +243 -0
- package/oclif.manifest.json +134 -59
- package/package.json +18 -26
- package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +0 -161
- package/dist/generator-templates/starter/app/routes/account_.recover.tsx +0 -129
- package/dist/generator-templates/starter/app/routes/account_.register.tsx +0 -207
- package/dist/generator-templates/starter/app/routes/account_.reset.$id.$resetToken.tsx +0 -136
- package/dist/virtual-routes/routes/debug-network.jsx +0 -289
- /package/dist/generator-templates/starter/app/{utils.ts → lib/variants.ts} +0 -0
|
@@ -2,14 +2,18 @@ import { vi, describe, expect, beforeEach, afterEach, it } from 'vitest';
|
|
|
2
2
|
import { login } from '../../lib/auth.js';
|
|
3
3
|
import { getStorefronts } from '../../lib/graphql/admin/link-storefront.js';
|
|
4
4
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { writeFile } from '@shopify/cli-kit/node/fs';
|
|
6
|
+
import { renderSelectPrompt, renderSuccess, renderWarning, renderFatalError } from '@shopify/cli-kit/node/ui';
|
|
7
|
+
import { ensureIsClean, GitDirectoryNotCleanError, getLatestGitCommit } from '@shopify/cli-kit/node/git';
|
|
7
8
|
import { oxygenDeploy, deploymentLogger } from './deploy.js';
|
|
8
9
|
import { getOxygenDeploymentData } from '../../lib/get-oxygen-deployment-data.js';
|
|
9
10
|
import { createDeploy, parseToken } from '@shopify/oxygen-cli/deploy';
|
|
11
|
+
import { ciPlatform } from '@shopify/cli-kit/node/context/local';
|
|
10
12
|
|
|
11
13
|
vi.mock("../../lib/get-oxygen-deployment-data.js");
|
|
12
14
|
vi.mock("@shopify/oxygen-cli/deploy");
|
|
15
|
+
vi.mock("@shopify/cli-kit/node/fs");
|
|
16
|
+
vi.mock("@shopify/cli-kit/node/context/local");
|
|
13
17
|
vi.mock("../../lib/auth.js");
|
|
14
18
|
vi.mock("../../lib/shopify-config.js");
|
|
15
19
|
vi.mock("../../lib/graphql/admin/link-storefront.js");
|
|
@@ -30,17 +34,16 @@ vi.mock("@shopify/cli-kit/node/ui", async () => {
|
|
|
30
34
|
renderFatalError: vi.fn(),
|
|
31
35
|
renderSelectPrompt: vi.fn(),
|
|
32
36
|
renderSuccess: vi.fn(),
|
|
33
|
-
renderTasks: vi.fn()
|
|
37
|
+
renderTasks: vi.fn(),
|
|
38
|
+
renderWarning: vi.fn()
|
|
34
39
|
};
|
|
35
40
|
});
|
|
36
41
|
vi.mock("@shopify/cli-kit/node/git", async () => {
|
|
42
|
+
const actual = await vi.importActual("@shopify/cli-kit/node/git");
|
|
37
43
|
return {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
vi.mock("@shopify/cli-kit/node/context/local", async () => {
|
|
42
|
-
return {
|
|
43
|
-
ciPlatform: () => ({ isCI: false })
|
|
44
|
+
...actual,
|
|
45
|
+
getLatestGitCommit: vi.fn(),
|
|
46
|
+
ensureIsClean: vi.fn()
|
|
44
47
|
};
|
|
45
48
|
});
|
|
46
49
|
describe("deploy", () => {
|
|
@@ -63,9 +66,12 @@ describe("deploy", () => {
|
|
|
63
66
|
};
|
|
64
67
|
const originalExit = process.exit;
|
|
65
68
|
const deployParams = {
|
|
69
|
+
authBypassToken: true,
|
|
70
|
+
defaultEnvironment: false,
|
|
71
|
+
force: false,
|
|
72
|
+
noJsonOutput: false,
|
|
66
73
|
path: "./",
|
|
67
74
|
shop: "snowdevil.myshopify.com",
|
|
68
|
-
publicDeployment: false,
|
|
69
75
|
metadataUrl: "https://example.com",
|
|
70
76
|
metadataUser: "user",
|
|
71
77
|
metadataVersion: "1.0.0"
|
|
@@ -82,15 +88,16 @@ describe("deploy", () => {
|
|
|
82
88
|
const expectedConfig = {
|
|
83
89
|
assetsDir: "dist/client",
|
|
84
90
|
bugsnag: true,
|
|
91
|
+
defaultEnvironment: false,
|
|
85
92
|
deploymentUrl: "https://oxygen.shopifyapps.com",
|
|
86
93
|
deploymentToken: mockToken,
|
|
94
|
+
generateAuthBypassToken: true,
|
|
87
95
|
verificationMaxDuration: 180,
|
|
88
96
|
metadata: {
|
|
89
97
|
url: deployParams.metadataUrl,
|
|
90
98
|
user: deployParams.metadataUser,
|
|
91
99
|
version: deployParams.metadataVersion
|
|
92
100
|
},
|
|
93
|
-
publicDeployment: deployParams.publicDeployment,
|
|
94
101
|
skipVerification: false,
|
|
95
102
|
rootPath: deployParams.path,
|
|
96
103
|
skipBuild: false,
|
|
@@ -99,10 +106,13 @@ describe("deploy", () => {
|
|
|
99
106
|
};
|
|
100
107
|
const expectedHooks = {
|
|
101
108
|
buildFunction: expect.any(Function),
|
|
109
|
+
onDeploymentCompleted: expect.any(Function),
|
|
110
|
+
onDeploymentFailed: expect.any(Function),
|
|
111
|
+
onDeploymentCompletedVerificationError: expect.any(Function),
|
|
102
112
|
onVerificationComplete: expect.any(Function),
|
|
113
|
+
onVerificationError: expect.any(Function),
|
|
103
114
|
onUploadFilesStart: expect.any(Function),
|
|
104
115
|
onUploadFilesComplete: expect.any(Function),
|
|
105
|
-
onVerificationError: expect.any(Function),
|
|
106
116
|
onUploadFilesError: expect.any(Function)
|
|
107
117
|
};
|
|
108
118
|
beforeEach(async () => {
|
|
@@ -111,6 +121,7 @@ describe("deploy", () => {
|
|
|
111
121
|
session: ADMIN_SESSION,
|
|
112
122
|
config: UNLINKED_SHOPIFY_CONFIG
|
|
113
123
|
});
|
|
124
|
+
vi.mocked(ciPlatform).mockReturnValue({ isCI: false });
|
|
114
125
|
vi.mocked(getStorefronts).mockResolvedValue([
|
|
115
126
|
{
|
|
116
127
|
...FULL_SHOPIFY_CONFIG.storefront,
|
|
@@ -119,9 +130,10 @@ describe("deploy", () => {
|
|
|
119
130
|
}
|
|
120
131
|
]);
|
|
121
132
|
vi.mocked(renderSelectPrompt).mockResolvedValue(FULL_SHOPIFY_CONFIG.shop);
|
|
122
|
-
vi.mocked(createDeploy).mockResolvedValue(
|
|
123
|
-
"
|
|
124
|
-
|
|
133
|
+
vi.mocked(createDeploy).mockResolvedValue({
|
|
134
|
+
authBypassToken: "some-token",
|
|
135
|
+
url: "https://a-lovely-deployment.com"
|
|
136
|
+
});
|
|
125
137
|
vi.mocked(getOxygenDeploymentData).mockResolvedValue({
|
|
126
138
|
oxygenDeploymentToken: "some-encoded-token",
|
|
127
139
|
environments: []
|
|
@@ -149,6 +161,81 @@ describe("deploy", () => {
|
|
|
149
161
|
});
|
|
150
162
|
expect(vi.mocked(renderSuccess)).toHaveBeenCalled;
|
|
151
163
|
});
|
|
164
|
+
it("errors when there are uncommited changes", async () => {
|
|
165
|
+
vi.mocked(ensureIsClean).mockRejectedValue(
|
|
166
|
+
new GitDirectoryNotCleanError("Uncommitted changes")
|
|
167
|
+
);
|
|
168
|
+
await expect(oxygenDeploy(deployParams)).rejects.toThrowError(
|
|
169
|
+
"Uncommitted changes detected"
|
|
170
|
+
);
|
|
171
|
+
expect(vi.mocked(createDeploy)).not.toHaveBeenCalled;
|
|
172
|
+
});
|
|
173
|
+
it("proceeds with warning and modified description when there are uncommited changes and the force flag is used", async () => {
|
|
174
|
+
vi.mocked(ensureIsClean).mockRejectedValue(
|
|
175
|
+
new GitDirectoryNotCleanError("Uncommitted changes")
|
|
176
|
+
);
|
|
177
|
+
vi.mocked(getLatestGitCommit).mockResolvedValue({
|
|
178
|
+
hash: "123",
|
|
179
|
+
message: "test commit",
|
|
180
|
+
date: "2021-01-01",
|
|
181
|
+
author_name: "test author",
|
|
182
|
+
author_email: "test@author.com",
|
|
183
|
+
body: "test body",
|
|
184
|
+
refs: "HEAD -> main"
|
|
185
|
+
});
|
|
186
|
+
await oxygenDeploy({
|
|
187
|
+
...deployParams,
|
|
188
|
+
force: true
|
|
189
|
+
});
|
|
190
|
+
expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({
|
|
191
|
+
headline: "No deployment description provided",
|
|
192
|
+
body: expect.anything()
|
|
193
|
+
});
|
|
194
|
+
expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
|
|
195
|
+
config: {
|
|
196
|
+
...expectedConfig,
|
|
197
|
+
environmentTag: "main",
|
|
198
|
+
metadata: {
|
|
199
|
+
...expectedConfig.metadata,
|
|
200
|
+
description: "123 with additional changes"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
hooks: expectedHooks,
|
|
204
|
+
logger: deploymentLogger
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
it("proceeds with provided description without warning when there are uncommited changes and the force flag is used", async () => {
|
|
208
|
+
vi.mocked(ensureIsClean).mockRejectedValue(
|
|
209
|
+
new GitDirectoryNotCleanError("Uncommitted changes")
|
|
210
|
+
);
|
|
211
|
+
vi.mocked(getLatestGitCommit).mockResolvedValue({
|
|
212
|
+
hash: "123",
|
|
213
|
+
message: "test commit",
|
|
214
|
+
date: "2021-01-01",
|
|
215
|
+
author_name: "test author",
|
|
216
|
+
author_email: "test@author.com",
|
|
217
|
+
body: "test body",
|
|
218
|
+
refs: "HEAD -> main"
|
|
219
|
+
});
|
|
220
|
+
await oxygenDeploy({
|
|
221
|
+
...deployParams,
|
|
222
|
+
force: true,
|
|
223
|
+
metadataDescription: "cool new stuff"
|
|
224
|
+
});
|
|
225
|
+
expect(vi.mocked(renderWarning)).not.toHaveBeenCalled;
|
|
226
|
+
expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
|
|
227
|
+
config: {
|
|
228
|
+
...expectedConfig,
|
|
229
|
+
environmentTag: "main",
|
|
230
|
+
metadata: {
|
|
231
|
+
...expectedConfig.metadata,
|
|
232
|
+
description: "cool new stuff"
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
hooks: expectedHooks,
|
|
236
|
+
logger: deploymentLogger
|
|
237
|
+
});
|
|
238
|
+
});
|
|
152
239
|
it("calls createDeploy with the checked out branch name", async () => {
|
|
153
240
|
vi.mocked(getLatestGitCommit).mockResolvedValue({
|
|
154
241
|
hash: "123",
|
|
@@ -171,19 +258,77 @@ describe("deploy", () => {
|
|
|
171
258
|
vi.mocked(getOxygenDeploymentData).mockResolvedValue({
|
|
172
259
|
oxygenDeploymentToken: "some-encoded-token",
|
|
173
260
|
environments: [
|
|
174
|
-
{ name: "
|
|
175
|
-
{ name: "
|
|
261
|
+
{ name: "Production", branch: "main", type: "PRODUCTION" },
|
|
262
|
+
{ name: "Preview", branch: null, type: "PREVIEW" }
|
|
176
263
|
]
|
|
177
264
|
});
|
|
178
265
|
await oxygenDeploy(deployParams);
|
|
179
266
|
expect(vi.mocked(renderSelectPrompt)).toHaveBeenCalledWith({
|
|
180
267
|
message: "Select an environment to deploy to",
|
|
181
268
|
choices: [
|
|
182
|
-
{ label: "
|
|
183
|
-
{ label: "
|
|
269
|
+
{ label: "Production", value: "main" },
|
|
270
|
+
{ label: "Preview", value: "shopify-preview-environment." }
|
|
184
271
|
]
|
|
185
272
|
});
|
|
186
273
|
});
|
|
274
|
+
describe("when Preview is selected", () => {
|
|
275
|
+
it("calls createDeploy with defaultEnvironment and an undefined environmentTag", async () => {
|
|
276
|
+
vi.mocked(getLatestGitCommit).mockResolvedValue({
|
|
277
|
+
hash: "123",
|
|
278
|
+
message: "test commit",
|
|
279
|
+
date: "2021-01-01",
|
|
280
|
+
author_name: "test author",
|
|
281
|
+
author_email: "test@author.com",
|
|
282
|
+
body: "test body",
|
|
283
|
+
refs: "HEAD -> main"
|
|
284
|
+
});
|
|
285
|
+
vi.mocked(getOxygenDeploymentData).mockResolvedValue({
|
|
286
|
+
oxygenDeploymentToken: "some-encoded-token",
|
|
287
|
+
environments: [
|
|
288
|
+
{ name: "Production", branch: "main", type: "PRODUCTION" },
|
|
289
|
+
{ name: "Preview", branch: null, type: "PREVIEW" }
|
|
290
|
+
]
|
|
291
|
+
});
|
|
292
|
+
vi.mocked(renderSelectPrompt).mockResolvedValue(
|
|
293
|
+
"shopify-preview-environment."
|
|
294
|
+
);
|
|
295
|
+
await oxygenDeploy(deployParams);
|
|
296
|
+
expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
|
|
297
|
+
config: {
|
|
298
|
+
...expectedConfig,
|
|
299
|
+
defaultEnvironment: true,
|
|
300
|
+
environmentTag: void 0
|
|
301
|
+
},
|
|
302
|
+
hooks: expectedHooks,
|
|
303
|
+
logger: deploymentLogger
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
it("writes a file with JSON content in CI environments", async () => {
|
|
308
|
+
vi.mocked(ciPlatform).mockReturnValue({
|
|
309
|
+
isCI: true,
|
|
310
|
+
name: "github",
|
|
311
|
+
metadata: {}
|
|
312
|
+
});
|
|
313
|
+
const ciDeployParams = {
|
|
314
|
+
...deployParams,
|
|
315
|
+
token: "some-token",
|
|
316
|
+
metadataDescription: "cool new stuff",
|
|
317
|
+
generateAuthBypassToken: true
|
|
318
|
+
};
|
|
319
|
+
await oxygenDeploy(ciDeployParams);
|
|
320
|
+
expect(vi.mocked(writeFile)).toHaveBeenCalledWith(
|
|
321
|
+
"h2_deploy_log.json",
|
|
322
|
+
JSON.stringify({
|
|
323
|
+
authBypassToken: "some-token",
|
|
324
|
+
url: "https://a-lovely-deployment.com"
|
|
325
|
+
})
|
|
326
|
+
);
|
|
327
|
+
vi.mocked(writeFile).mockClear();
|
|
328
|
+
ciDeployParams.noJsonOutput = true;
|
|
329
|
+
await oxygenDeploy(ciDeployParams);
|
|
330
|
+
expect(vi.mocked(writeFile)).not.toHaveBeenCalled();
|
|
331
|
+
});
|
|
187
332
|
it("handles error during uploadFiles", async () => {
|
|
188
333
|
const mockRenderFatalError = vi.fn();
|
|
189
334
|
vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
|
|
@@ -209,7 +354,7 @@ describe("deploy", () => {
|
|
|
209
354
|
}
|
|
210
355
|
}
|
|
211
356
|
});
|
|
212
|
-
it("handles error during deployment verification", async () => {
|
|
357
|
+
it("handles error during deployment routability verification", async () => {
|
|
213
358
|
const mockRenderFatalError = vi.fn();
|
|
214
359
|
vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
|
|
215
360
|
const error = new Error("Cloudflare is down!");
|
|
@@ -235,4 +380,31 @@ describe("deploy", () => {
|
|
|
235
380
|
}
|
|
236
381
|
}
|
|
237
382
|
});
|
|
383
|
+
it("handles error during deployment completion verification", async () => {
|
|
384
|
+
const mockRenderFatalError = vi.fn();
|
|
385
|
+
vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
|
|
386
|
+
vi.mocked(createDeploy).mockImplementation((options) => {
|
|
387
|
+
options.hooks?.onUploadFilesStart?.();
|
|
388
|
+
options.hooks?.onUploadFilesComplete?.();
|
|
389
|
+
options.hooks?.onDeploymentCompletedVerificationStart?.();
|
|
390
|
+
options.hooks?.onDeploymentFailed?.({
|
|
391
|
+
status: "oh shit",
|
|
392
|
+
url: "https://a-lovely-deployment.com"
|
|
393
|
+
});
|
|
394
|
+
return new Promise((_resolve, reject) => {
|
|
395
|
+
reject();
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
try {
|
|
399
|
+
await oxygenDeploy(deployParams);
|
|
400
|
+
expect(true).toBe(false);
|
|
401
|
+
} catch (err) {
|
|
402
|
+
if (err instanceof AbortError) {
|
|
403
|
+
expect(err.message).toBe("oh shit");
|
|
404
|
+
expect(err.tryMessage).toBe("Retrying the deployement may succeed.");
|
|
405
|
+
} else {
|
|
406
|
+
expect(true).toBe(false);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
});
|
|
238
410
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs/promises';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
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';
|
|
@@ -7,11 +7,10 @@ import colors from '@shopify/cli-kit/node/colors';
|
|
|
7
7
|
import { copyPublicFiles } from './build.js';
|
|
8
8
|
import { getProjectPaths, assertOxygenChecks, handleRemixImportFail, getRemixConfig } from '../../lib/remix-config.js';
|
|
9
9
|
import { muteDevLogs, createRemixLogger, enhanceH2Logs } from '../../lib/log.js';
|
|
10
|
-
import { commonFlags,
|
|
10
|
+
import { commonFlags, deprecated, overrideFlag, flagsToCamelObject } from '../../lib/flags.js';
|
|
11
11
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
12
12
|
import { Flags } from '@oclif/core';
|
|
13
|
-
import { startMiniOxygen } from '../../lib/mini-oxygen/index.js';
|
|
14
|
-
import { checkHydrogenVersion } from '../../lib/check-version.js';
|
|
13
|
+
import { buildAssetsUrl, startMiniOxygen } from '../../lib/mini-oxygen/index.js';
|
|
15
14
|
import { addVirtualRoutes } from '../../lib/virtual-routes.js';
|
|
16
15
|
import { spawnCodegenProcess } from '../../lib/codegen.js';
|
|
17
16
|
import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
|
|
@@ -19,6 +18,9 @@ import { getConfig } from '../../lib/shopify-config.js';
|
|
|
19
18
|
import { setupLiveReload } from '../../lib/live-reload.js';
|
|
20
19
|
import { checkRemixVersions } from '../../lib/remix-version-check.js';
|
|
21
20
|
import { getGraphiQLUrl } from '../../lib/graphiql-url.js';
|
|
21
|
+
import { displayDevUpgradeNotice } from './upgrade.js';
|
|
22
|
+
import { findPort } from '../../lib/find-port.js';
|
|
23
|
+
import { prepareDiffDirectory } from '../../lib/template-diff.js';
|
|
22
24
|
|
|
23
25
|
const LOG_REBUILDING = "\u{1F9F1} Rebuilding...";
|
|
24
26
|
const LOG_REBUILT = "\u{1F680} Rebuilt";
|
|
@@ -27,7 +29,8 @@ class Dev extends Command {
|
|
|
27
29
|
static flags = {
|
|
28
30
|
path: commonFlags.path,
|
|
29
31
|
port: commonFlags.port,
|
|
30
|
-
|
|
32
|
+
worker: deprecated("--worker", { isBoolean: true }),
|
|
33
|
+
"legacy-runtime": commonFlags.legacyRuntime,
|
|
31
34
|
codegen: overrideFlag(commonFlags.codegen, {
|
|
32
35
|
description: commonFlags.codegen.description + " It updates the types on file save."
|
|
33
36
|
}),
|
|
@@ -38,43 +41,45 @@ class Dev extends Command {
|
|
|
38
41
|
env: "SHOPIFY_HYDROGEN_FLAG_DISABLE_VIRTUAL_ROUTES",
|
|
39
42
|
default: false
|
|
40
43
|
}),
|
|
41
|
-
debug:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
debug: commonFlags.debug,
|
|
45
|
+
"inspector-port": commonFlags.inspectorPort,
|
|
46
|
+
["env-branch"]: commonFlags.envBranch,
|
|
47
|
+
["disable-version-check"]: Flags.boolean({
|
|
48
|
+
description: "Skip the version check when running `hydrogen dev`",
|
|
49
|
+
default: false,
|
|
50
|
+
required: false
|
|
45
51
|
}),
|
|
46
|
-
|
|
47
|
-
["env-branch"]: commonFlags.envBranch
|
|
52
|
+
diff: commonFlags.diff
|
|
48
53
|
};
|
|
49
54
|
async run() {
|
|
50
55
|
const { flags } = await this.parse(Dev);
|
|
51
|
-
|
|
56
|
+
let directory = flags.path ? path.resolve(flags.path) : process.cwd();
|
|
57
|
+
if (flags.diff) {
|
|
58
|
+
directory = await prepareDiffDirectory(directory, true);
|
|
59
|
+
}
|
|
52
60
|
await runDev({
|
|
53
61
|
...flagsToCamelObject(flags),
|
|
54
|
-
useCodegen: flags.codegen,
|
|
55
|
-
workerRuntime: flags["worker-unstable"],
|
|
56
62
|
path: directory
|
|
57
63
|
});
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
async function runDev({
|
|
61
|
-
port:
|
|
67
|
+
port: appPort,
|
|
62
68
|
path: appPath,
|
|
63
|
-
useCodegen = false,
|
|
64
|
-
|
|
69
|
+
codegen: useCodegen = false,
|
|
70
|
+
legacyRuntime = false,
|
|
65
71
|
codegenConfigPath,
|
|
66
72
|
disableVirtualRoutes,
|
|
67
73
|
envBranch,
|
|
68
74
|
debug = false,
|
|
69
|
-
sourcemap = true
|
|
75
|
+
sourcemap = true,
|
|
76
|
+
disableVersionCheck = false,
|
|
77
|
+
inspectorPort
|
|
70
78
|
}) {
|
|
71
79
|
if (!process.env.NODE_ENV)
|
|
72
80
|
process.env.NODE_ENV = "development";
|
|
73
81
|
muteDevLogs();
|
|
74
|
-
if (debug)
|
|
75
|
-
(await import('node:inspector')).open();
|
|
76
82
|
const { root, publicPath, buildPathClient, buildPathWorkerFile } = getProjectPaths(appPath);
|
|
77
|
-
const checkingHydrogenVersion = checkHydrogenVersion(root);
|
|
78
83
|
const copyingFiles = copyPublicFiles(publicPath, buildPathClient);
|
|
79
84
|
const reloadConfig = async () => {
|
|
80
85
|
const config = await getRemixConfig(root);
|
|
@@ -90,6 +95,12 @@ async function runDev({
|
|
|
90
95
|
return [fileRelative, path.resolve(root, fileRelative)];
|
|
91
96
|
};
|
|
92
97
|
const serverBundleExists = () => fileExists(buildPathWorkerFile);
|
|
98
|
+
inspectorPort = debug ? await findPort(inspectorPort) : inspectorPort;
|
|
99
|
+
appPort = legacyRuntime ? appPort : await findPort(appPort);
|
|
100
|
+
const assetsPort = legacyRuntime ? 0 : await findPort(appPort + 100);
|
|
101
|
+
if (assetsPort) {
|
|
102
|
+
process.env.HYDROGEN_ASSET_BASE_URL = buildAssetsUrl(assetsPort);
|
|
103
|
+
}
|
|
93
104
|
const [remixConfig, { shop, storefront }] = await Promise.all([
|
|
94
105
|
reloadConfig(),
|
|
95
106
|
getConfig(root)
|
|
@@ -106,19 +117,23 @@ async function runDev({
|
|
|
106
117
|
let initialBuildStartTimeMs = Date.now();
|
|
107
118
|
const liveReload = await setupLiveReload(remixConfig.dev?.port ?? 8002) ;
|
|
108
119
|
let miniOxygen;
|
|
120
|
+
let codegenProcess;
|
|
109
121
|
async function safeStartMiniOxygen() {
|
|
110
122
|
if (miniOxygen)
|
|
111
123
|
return;
|
|
112
124
|
miniOxygen = await startMiniOxygen(
|
|
113
125
|
{
|
|
114
126
|
root,
|
|
115
|
-
|
|
127
|
+
debug,
|
|
128
|
+
assetsPort,
|
|
129
|
+
inspectorPort,
|
|
130
|
+
port: appPort,
|
|
116
131
|
watch: !liveReload,
|
|
117
132
|
buildPathWorkerFile,
|
|
118
133
|
buildPathClient,
|
|
119
134
|
env: await envPromise
|
|
120
135
|
},
|
|
121
|
-
|
|
136
|
+
legacyRuntime
|
|
122
137
|
);
|
|
123
138
|
enhanceH2Logs({ host: miniOxygen.listeningAt, ...remixConfig });
|
|
124
139
|
miniOxygen.showBanner({
|
|
@@ -134,21 +149,24 @@ View GraphiQL API browser: ${getGraphiQLUrl({
|
|
|
134
149
|
),
|
|
135
150
|
colors.dim(
|
|
136
151
|
`
|
|
137
|
-
View server
|
|
152
|
+
View server network requests: ${miniOxygen.listeningAt}/subrequest-profiler`
|
|
138
153
|
)
|
|
139
154
|
]
|
|
140
155
|
});
|
|
141
156
|
if (useCodegen) {
|
|
142
|
-
spawnCodegenProcess({
|
|
157
|
+
codegenProcess = spawnCodegenProcess({
|
|
158
|
+
...remixConfig,
|
|
159
|
+
configFilePath: codegenConfigPath
|
|
160
|
+
});
|
|
143
161
|
}
|
|
144
162
|
checkRemixVersions();
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
163
|
+
if (!disableVersionCheck) {
|
|
164
|
+
displayDevUpgradeNotice({ targetPath: appPath });
|
|
165
|
+
}
|
|
148
166
|
}
|
|
149
167
|
const fileWatchCache = createFileWatchCache();
|
|
150
168
|
let skipRebuildLogs = false;
|
|
151
|
-
await watch(
|
|
169
|
+
const closeWatcher = await watch(
|
|
152
170
|
{
|
|
153
171
|
config: remixConfig,
|
|
154
172
|
options: {
|
|
@@ -184,6 +202,7 @@ View server-side network requests: ${miniOxygen.listeningAt}/debug-network`
|
|
|
184
202
|
name: "BuildError",
|
|
185
203
|
type: 0,
|
|
186
204
|
message: "MiniOxygen cannot start because the server bundle has not been generated.",
|
|
205
|
+
skipOclifErrorHandling: true,
|
|
187
206
|
tryMessage: "This is likely due to an error in your app and Remix is unable to compile. Try fixing the app and MiniOxygen will start."
|
|
188
207
|
});
|
|
189
208
|
}
|
|
@@ -240,6 +259,12 @@ View server-side network requests: ${miniOxygen.listeningAt}/debug-network`
|
|
|
240
259
|
}
|
|
241
260
|
}
|
|
242
261
|
);
|
|
262
|
+
return {
|
|
263
|
+
async close() {
|
|
264
|
+
codegenProcess?.kill(0);
|
|
265
|
+
await Promise.all([closeWatcher(), miniOxygen?.close()]);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
243
268
|
}
|
|
244
269
|
|
|
245
|
-
export { Dev as default };
|
|
270
|
+
export { Dev as default, runDev };
|
|
@@ -27,7 +27,7 @@ class Init extends Command {
|
|
|
27
27
|
env: "SHOPIFY_HYDROGEN_FLAG_LANGUAGE"
|
|
28
28
|
}),
|
|
29
29
|
template: Flags.string({
|
|
30
|
-
description: "
|
|
30
|
+
description: "Scaffolds project based on an existing template or example from the Hydrogen repository.",
|
|
31
31
|
env: "SHOPIFY_HYDROGEN_FLAG_TEMPLATE"
|
|
32
32
|
}),
|
|
33
33
|
"install-deps": commonFlags.installDeps,
|