@shopify/cli-hydrogen 7.1.1 → 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.
- package/dist/commands/hydrogen/build-vite.js +19 -10
- package/dist/commands/hydrogen/build.js +10 -2
- package/dist/commands/hydrogen/check.js +1 -0
- package/dist/commands/hydrogen/codegen.js +1 -0
- package/dist/commands/hydrogen/customer-account/push.js +170 -0
- package/dist/commands/hydrogen/debug/cpu.js +3 -0
- package/dist/commands/hydrogen/deploy.js +121 -36
- package/dist/commands/hydrogen/dev-vite.js +128 -59
- package/dist/commands/hydrogen/dev.js +108 -51
- package/dist/commands/hydrogen/env/list.js +7 -8
- package/dist/commands/hydrogen/env/pull.js +17 -1
- package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
- package/dist/commands/hydrogen/generate/route.js +1 -0
- package/dist/commands/hydrogen/init.js +45 -17
- package/dist/commands/hydrogen/link.js +20 -4
- package/dist/commands/hydrogen/list.js +1 -0
- package/dist/commands/hydrogen/login.js +1 -0
- package/dist/commands/hydrogen/logout.js +1 -0
- package/dist/commands/hydrogen/preview.js +31 -16
- package/dist/commands/hydrogen/setup/css.js +8 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -0
- package/dist/commands/hydrogen/setup/vite.js +244 -138
- package/dist/commands/hydrogen/setup.js +21 -22
- package/dist/commands/hydrogen/shortcut.js +10 -0
- package/dist/commands/hydrogen/unlink.js +1 -0
- package/dist/commands/hydrogen/upgrade.js +2 -1
- package/dist/generator-templates/assets/vite/package.json +2 -3
- package/dist/generator-templates/assets/vite/vite.config.js +10 -2
- package/dist/generator-templates/starter/CHANGELOG.md +104 -0
- package/dist/generator-templates/starter/README.md +3 -44
- package/dist/generator-templates/starter/app/components/Search.tsx +12 -7
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
- package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
- package/dist/generator-templates/starter/app/root.tsx +2 -5
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +8 -15
- package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
- package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
- package/dist/generator-templates/starter/package.json +14 -9
- package/dist/generator-templates/starter/server.ts +2 -1
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
- package/dist/generator-templates/starter/vite.config.ts +21 -0
- package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
- package/dist/lib/check-lockfile.js +12 -18
- package/dist/lib/codegen.js +37 -13
- package/dist/lib/common.js +50 -0
- package/dist/lib/cpu-profiler.js +4 -1
- package/dist/lib/dev-shared.js +97 -0
- package/dist/lib/environment-variables.js +51 -30
- package/dist/lib/file.js +8 -1
- package/dist/lib/flags.js +37 -16
- package/dist/lib/graphql/admin/customer-application-update.js +29 -0
- package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
- package/dist/lib/graphql/admin/list-environments.js +1 -0
- package/dist/lib/graphql/admin/pull-variables.js +4 -4
- package/dist/lib/graphql/admin/test-helper.js +37 -0
- package/dist/lib/log.js +86 -13
- package/dist/lib/mini-oxygen/common.js +19 -33
- package/dist/lib/mini-oxygen/index.js +6 -2
- package/dist/lib/mini-oxygen/node.js +43 -31
- package/dist/lib/mini-oxygen/workerd.js +72 -165
- package/dist/lib/missing-routes.js +1 -1
- package/dist/lib/onboarding/common.js +82 -70
- package/dist/lib/onboarding/local.js +19 -9
- package/dist/lib/onboarding/remote.js +35 -30
- package/dist/lib/package-managers.js +24 -0
- package/dist/lib/remix-config.js +17 -1
- package/dist/lib/request-events.js +6 -1
- package/dist/lib/setups/i18n/replacers.js +9 -6
- package/dist/lib/setups/routes/generate.js +1 -0
- package/dist/lib/shell.js +2 -1
- package/dist/lib/shopify-config.js +19 -1
- package/dist/lib/template-diff.js +36 -15
- package/dist/lib/template-downloader.js +35 -5
- package/dist/lib/transpile/morph/typedefs.js +5 -2
- package/dist/lib/transpile/project.js +8 -4
- package/dist/lib/tunneling.js +44 -0
- package/dist/lib/virtual-routes.js +1 -1
- package/dist/lib/vite-config.js +39 -9
- package/oclif.manifest.json +711 -498
- package/package.json +30 -22
- package/dist/commands/hydrogen/deploy.test.js +0 -553
- package/dist/commands/hydrogen/env/list.test.js +0 -148
- package/dist/commands/hydrogen/env/pull.test.js +0 -207
- package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
- package/dist/commands/hydrogen/generate/route.test.js +0 -43
- package/dist/commands/hydrogen/init.test.js +0 -641
- package/dist/commands/hydrogen/link.test.js +0 -187
- package/dist/commands/hydrogen/list.test.js +0 -111
- package/dist/commands/hydrogen/setup.test.js +0 -61
- package/dist/commands/hydrogen/shortcut.test.js +0 -30
- package/dist/commands/hydrogen/unlink.test.js +0 -36
- package/dist/commands/hydrogen/upgrade.test.js +0 -786
- package/dist/generator-templates/starter/remix.config.js +0 -24
- package/dist/lib/auth.test.js +0 -157
- package/dist/lib/check-lockfile.test.js +0 -81
- package/dist/lib/check-version.test.js +0 -86
- package/dist/lib/environment-variables.test.js +0 -149
- package/dist/lib/file.test.js +0 -68
- package/dist/lib/flags.test.js +0 -43
- package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
- package/dist/lib/gid.test.js +0 -15
- package/dist/lib/graphql/admin/client.test.js +0 -76
- package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
- package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
- package/dist/lib/graphql/admin/list-environments.test.js +0 -44
- package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
- package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
- package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
- package/dist/lib/log.test.js +0 -92
- package/dist/lib/mini-oxygen/assets.js +0 -134
- package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
- package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
- package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
- package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
- package/dist/lib/missing-routes.test.js +0 -45
- package/dist/lib/remix-version-check.test.js +0 -39
- package/dist/lib/remix-version-interop.test.js +0 -13
- package/dist/lib/setups/i18n/domains.test.js +0 -39
- package/dist/lib/setups/i18n/replacers.test.js +0 -261
- package/dist/lib/setups/i18n/subdomains.test.js +0 -39
- package/dist/lib/setups/i18n/subfolders.test.js +0 -39
- package/dist/lib/setups/routes/generate.test.js +0 -296
- package/dist/lib/shell.test.js +0 -111
- package/dist/lib/shopify-config.test.js +0 -199
- package/dist/lib/string.test.js +0 -16
- package/dist/lib/virtual-routes.test.js +0 -49
- package/dist/lib/vite/hydrogen-middleware.js +0 -82
- package/dist/lib/vite/mini-oxygen.js +0 -152
- package/dist/lib/vite/plugins.d.ts +0 -27
- package/dist/lib/vite/plugins.js +0 -139
- package/dist/lib/vite/shared.js +0 -10
- package/dist/lib/vite/utils.js +0 -55
- package/dist/lib/vite/worker-entry.js +0 -1518
- /package/dist/generator-templates/starter/{.eslintrc.js → .eslintrc.cjs} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
|
-
import { outputWarn } from '@shopify/cli-kit/node/output';
|
|
2
|
+
import { collectLog, outputWarn } from '@shopify/cli-kit/node/output';
|
|
3
3
|
import { removeFile, fileSize } from '@shopify/cli-kit/node/fs';
|
|
4
4
|
import { resolvePath, joinPath } from '@shopify/cli-kit/node/path';
|
|
5
5
|
import { getPackageManager } from '@shopify/cli-kit/node/node-package-manager';
|
|
@@ -23,6 +23,7 @@ class Build extends Command {
|
|
|
23
23
|
...commonFlags.codegen,
|
|
24
24
|
...commonFlags.diff
|
|
25
25
|
};
|
|
26
|
+
static hidden = true;
|
|
26
27
|
async run() {
|
|
27
28
|
const { flags } = await this.parse(Build);
|
|
28
29
|
const originalDirectory = flags.path ? resolvePath(flags.path) : process.cwd();
|
|
@@ -57,20 +58,28 @@ async function runViteBuild({
|
|
|
57
58
|
if (lockfileCheck) {
|
|
58
59
|
await checkLockfileStatus(root, isCI());
|
|
59
60
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
remixConfig,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
const [
|
|
62
|
+
vite,
|
|
63
|
+
{ userViteConfig, remixConfig, clientOutDir, serverOutDir, serverOutFile }
|
|
64
|
+
] = await Promise.all([
|
|
65
|
+
// Avoid static imports because this file is imported by `deploy` command,
|
|
66
|
+
// which must have a hard dependency on 'vite'.
|
|
67
|
+
import('vite'),
|
|
68
|
+
getViteConfig(root, ssrEntry)
|
|
69
|
+
]);
|
|
70
|
+
const customLogger = vite.createLogger();
|
|
71
|
+
if (process.env.SHOPIFY_UNIT_TEST) {
|
|
72
|
+
customLogger.info = (msg) => collectLog("info", msg);
|
|
73
|
+
customLogger.warn = (msg) => collectLog("warn", msg);
|
|
74
|
+
customLogger.error = (msg) => collectLog("error", msg);
|
|
75
|
+
}
|
|
67
76
|
const serverMinify = userViteConfig.build?.minify ?? true;
|
|
68
77
|
const commonConfig = {
|
|
69
78
|
root,
|
|
70
79
|
mode: process.env.NODE_ENV,
|
|
71
|
-
base: assetPath
|
|
80
|
+
base: assetPath,
|
|
81
|
+
customLogger
|
|
72
82
|
};
|
|
73
|
-
const vite = await import('vite');
|
|
74
83
|
await vite.build({
|
|
75
84
|
...commonConfig,
|
|
76
85
|
build: {
|
|
@@ -14,10 +14,12 @@ import { codegen } from '../../lib/codegen.js';
|
|
|
14
14
|
import { buildBundleAnalysis, getBundleAnalysisSummary } from '../../lib/bundle/analyzer.js';
|
|
15
15
|
import { isCI } from '../../lib/is-ci.js';
|
|
16
16
|
import { prepareDiffDirectory, copyDiffBuild } from '../../lib/template-diff.js';
|
|
17
|
+
import { hasViteConfig } from '../../lib/vite-config.js';
|
|
17
18
|
|
|
18
19
|
const LOG_WORKER_BUILT = "\u{1F4E6} Worker built";
|
|
19
20
|
const WORKER_BUILD_SIZE_LIMIT = 5;
|
|
20
21
|
class Build extends Command {
|
|
22
|
+
static descriptionWithMarkdown = `Builds a Hydrogen storefront for production. The client and app worker files are compiled to a \`/dist\` folder in your Hydrogen project directory.`;
|
|
21
23
|
static description = "Builds a Hydrogen storefront for production.";
|
|
22
24
|
static flags = {
|
|
23
25
|
...commonFlags.path,
|
|
@@ -39,11 +41,17 @@ class Build extends Command {
|
|
|
39
41
|
if (flags.diff) {
|
|
40
42
|
directory = await prepareDiffDirectory(originalDirectory, false);
|
|
41
43
|
}
|
|
42
|
-
|
|
44
|
+
const buildParams = {
|
|
43
45
|
...flagsToCamelObject(flags),
|
|
44
46
|
useCodegen: flags.codegen,
|
|
45
47
|
directory
|
|
46
|
-
}
|
|
48
|
+
};
|
|
49
|
+
if (await hasViteConfig(directory ?? process.cwd())) {
|
|
50
|
+
const { runViteBuild } = await import('./build-vite.js');
|
|
51
|
+
await runViteBuild(buildParams);
|
|
52
|
+
} else {
|
|
53
|
+
await runBuild(buildParams);
|
|
54
|
+
}
|
|
47
55
|
if (flags.diff) {
|
|
48
56
|
await copyDiffBuild(directory, originalDirectory);
|
|
49
57
|
}
|
|
@@ -6,6 +6,7 @@ import { logMissingRoutes, findMissingRoutes } from '../../lib/missing-routes.js
|
|
|
6
6
|
import { Args } from '@oclif/core';
|
|
7
7
|
|
|
8
8
|
class GenerateRoute extends Command {
|
|
9
|
+
static descriptionWithMarkdown = `Checks whether your Hydrogen app includes a set of standard Shopify routes.`;
|
|
9
10
|
static description = "Returns diagnostic information about a Hydrogen storefront.";
|
|
10
11
|
static flags = {
|
|
11
12
|
...commonFlags.path
|
|
@@ -8,6 +8,7 @@ import { commonFlags, flagsToCamelObject } from '../../lib/flags.js';
|
|
|
8
8
|
import { codegen } from '../../lib/codegen.js';
|
|
9
9
|
|
|
10
10
|
class Codegen extends Command {
|
|
11
|
+
static descriptionWithMarkdown = "Automatically generates GraphQL types for your project\u2019s Storefront API queries.";
|
|
11
12
|
static description = "Generate types for the Storefront API queries found in your project.";
|
|
12
13
|
static flags = {
|
|
13
14
|
...commonFlags.path,
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
|
+
import { Flags } from '@oclif/core';
|
|
3
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
4
|
+
import { outputDebug } from '@shopify/cli-kit/node/output';
|
|
5
|
+
import { linkStorefront } from '../link.js';
|
|
6
|
+
import { commonFlags, flagsToCamelObject } from '../../../lib/flags.js';
|
|
7
|
+
import { getCliCommand } from '../../../lib/shell.js';
|
|
8
|
+
import { login } from '../../../lib/auth.js';
|
|
9
|
+
import { setCustomerAccountConfig, getConfig } from '../../../lib/shopify-config.js';
|
|
10
|
+
import { replaceCustomerApplicationUrls } from '../../../lib/graphql/admin/customer-application-update.js';
|
|
11
|
+
|
|
12
|
+
class CustomerAccountPush extends Command {
|
|
13
|
+
static description = "Push project configuration to admin";
|
|
14
|
+
static flags = {
|
|
15
|
+
...commonFlags.path,
|
|
16
|
+
"storefront-id": Flags.string({
|
|
17
|
+
description: "The id of the storefront the configuration should be pushed to. Must start with 'gid://shopify/HydrogenStorefront/'"
|
|
18
|
+
}),
|
|
19
|
+
"dev-origin": Flags.string({
|
|
20
|
+
description: "The development domain of your application.",
|
|
21
|
+
required: true
|
|
22
|
+
}),
|
|
23
|
+
"relative-redirect-uri": Flags.string({
|
|
24
|
+
description: "The relative url of allowed callback url for Customer Account API OAuth flow. Default is '/account/authorize'"
|
|
25
|
+
}),
|
|
26
|
+
"relative-logout-uri": Flags.string({
|
|
27
|
+
description: "The relative url of allowed url that will be redirected to post-logout for Customer Account API OAuth flow. Default to nothing."
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
async run() {
|
|
31
|
+
const { flags } = await this.parse(CustomerAccountPush);
|
|
32
|
+
await runCustomerAccountPush({ ...flagsToCamelObject(flags) });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function runCustomerAccountPush({
|
|
36
|
+
path: root = process.cwd(),
|
|
37
|
+
storefrontId: storefrontIdFromFlag,
|
|
38
|
+
devOrigin,
|
|
39
|
+
redirectUriRelativeUrl = "/account/authorize",
|
|
40
|
+
logoutUriRelativeUrl
|
|
41
|
+
}) {
|
|
42
|
+
const storefrontId = await getStorefrontId(root, storefrontIdFromFlag);
|
|
43
|
+
try {
|
|
44
|
+
if (!storefrontId) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
"No storefrontId was found in --storefront-id flag or .shopify/project.json"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const redirectUri = redirectUriRelativeUrl ? new URL(redirectUriRelativeUrl, devOrigin).toString() : devOrigin;
|
|
50
|
+
const javascriptOrigin = devOrigin;
|
|
51
|
+
const logoutUri = logoutUriRelativeUrl ? new URL(logoutUriRelativeUrl, devOrigin).toString() : devOrigin;
|
|
52
|
+
if (!redirectUri && !javascriptOrigin && !logoutUri) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { session, config } = await login(root);
|
|
56
|
+
const customerAccountConfig = config?.storefront?.customerAccountConfig;
|
|
57
|
+
const { success, userErrors } = await replaceCustomerApplicationUrls(
|
|
58
|
+
session,
|
|
59
|
+
storefrontId,
|
|
60
|
+
{
|
|
61
|
+
redirectUri: {
|
|
62
|
+
add: redirectUri ? [redirectUri] : void 0,
|
|
63
|
+
removeRegex: customerAccountConfig?.redirectUri
|
|
64
|
+
},
|
|
65
|
+
javascriptOrigin: {
|
|
66
|
+
add: javascriptOrigin ? [javascriptOrigin] : void 0,
|
|
67
|
+
removeRegex: customerAccountConfig?.javascriptOrigin
|
|
68
|
+
},
|
|
69
|
+
logoutUris: {
|
|
70
|
+
add: logoutUri ? [logoutUri] : void 0,
|
|
71
|
+
removeRegex: customerAccountConfig?.logoutUri
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
if (!success || userErrors.length) {
|
|
76
|
+
const error = new Error(
|
|
77
|
+
"Customer Account Application setup update fail."
|
|
78
|
+
);
|
|
79
|
+
error.userErrors = userErrors;
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
await setCustomerAccountConfig(root, {
|
|
83
|
+
redirectUri,
|
|
84
|
+
javascriptOrigin,
|
|
85
|
+
logoutUri
|
|
86
|
+
});
|
|
87
|
+
return () => cleanupCustomerApplicationUrls(session, storefrontId, {
|
|
88
|
+
redirectUri,
|
|
89
|
+
javascriptOrigin,
|
|
90
|
+
logoutUri
|
|
91
|
+
});
|
|
92
|
+
} catch (error) {
|
|
93
|
+
let confidentialAccessFound = false;
|
|
94
|
+
const errors = error?.userErrors?.length ? error.userErrors.map(
|
|
95
|
+
(value) => {
|
|
96
|
+
if (/Javascript origin is not allowed for this application type/i.test(
|
|
97
|
+
value.message
|
|
98
|
+
)) {
|
|
99
|
+
confidentialAccessFound = true;
|
|
100
|
+
}
|
|
101
|
+
return `${value.field}: ${value.message}`;
|
|
102
|
+
}
|
|
103
|
+
) : error.message ? [error.message] : [];
|
|
104
|
+
const nextSteps = [
|
|
105
|
+
{
|
|
106
|
+
link: {
|
|
107
|
+
label: "Manually update application setup",
|
|
108
|
+
url: "https://shopify.dev/docs/custom-storefronts/building-with-the-customer-account-api/hydrogen#update-the-application-setup"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
if (confidentialAccessFound) {
|
|
113
|
+
nextSteps.unshift({
|
|
114
|
+
link: {
|
|
115
|
+
label: "Enable Public access for Hydrogen",
|
|
116
|
+
url: "https://shopify.dev/docs/custom-storefronts/building-with-the-customer-account-api/getting-started#step-1-enable-customer-account-api-access"
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
throw new AbortError(
|
|
121
|
+
"Customer Account Application setup update fail.",
|
|
122
|
+
errors.length ? [
|
|
123
|
+
{
|
|
124
|
+
list: {
|
|
125
|
+
title: "The following error occurs during update:",
|
|
126
|
+
items: errors.map(
|
|
127
|
+
(value, index) => `${index != 0 ? "\n\n" : ""}${value}`
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
] : void 0,
|
|
132
|
+
nextSteps
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function cleanupCustomerApplicationUrls(session, storefrontId, customerAccountConfig = {}) {
|
|
137
|
+
if (!Object.values(customerAccountConfig).some(Boolean))
|
|
138
|
+
return;
|
|
139
|
+
outputDebug(
|
|
140
|
+
`Cleaning up Customer Application url "${customerAccountConfig.redirectUri}"`
|
|
141
|
+
);
|
|
142
|
+
await replaceCustomerApplicationUrls(session, storefrontId, {
|
|
143
|
+
redirectUri: { removeRegex: customerAccountConfig?.redirectUri },
|
|
144
|
+
javascriptOrigin: { removeRegex: customerAccountConfig?.javascriptOrigin },
|
|
145
|
+
logoutUris: { removeRegex: customerAccountConfig?.logoutUri }
|
|
146
|
+
}).catch((error) => {
|
|
147
|
+
outputDebug(
|
|
148
|
+
`Failed to clean up Customer Application url "${customerAccountConfig.redirectUri}":
|
|
149
|
+
${error?.message}`
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async function getStorefrontId(root, storefrontIdFromFlag) {
|
|
154
|
+
if (storefrontIdFromFlag)
|
|
155
|
+
return storefrontIdFromFlag;
|
|
156
|
+
const { session, config } = await login(root);
|
|
157
|
+
if (config.storefront?.id)
|
|
158
|
+
return config.storefront.id;
|
|
159
|
+
const cliCommand = await getCliCommand();
|
|
160
|
+
const linkedStore = await linkStorefront(root, session, config, {
|
|
161
|
+
cliCommand
|
|
162
|
+
});
|
|
163
|
+
if (!linkedStore) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const newConfig = await getConfig(root);
|
|
167
|
+
return newConfig.storefront?.id;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export { CustomerAccountPush as default, getStorefrontId, runCustomerAccountPush };
|
|
@@ -12,6 +12,9 @@ import { createCpuStartupProfiler } from '../../../lib/cpu-profiler.js';
|
|
|
12
12
|
|
|
13
13
|
const DEFAULT_OUTPUT_PATH = "startup.cpuprofile";
|
|
14
14
|
class DebugCpu extends Command {
|
|
15
|
+
static descriptionWithMarkdown = `Builds the app and runs the resulting code to profile the server startup time, watching for changes. This command can be used to [debug slow app startup times](https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/cpu-startup) that cause failed deployments in Oxygen.
|
|
16
|
+
|
|
17
|
+
The profiling results are written to a \`.cpuprofile\` file that can be viewed with certain tools such as [Flame Chart Visualizer for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-js-profile-flame).`;
|
|
15
18
|
static description = "Builds and profiles the server startup time the app.";
|
|
16
19
|
static flags = {
|
|
17
20
|
...commonFlags.path,
|
|
@@ -7,15 +7,19 @@ import { AbortError } from '@shopify/cli-kit/node/error';
|
|
|
7
7
|
import { writeFile } from '@shopify/cli-kit/node/fs';
|
|
8
8
|
import { ensureIsClean, getLatestGitCommit, GitDirectoryNotCleanError } from '@shopify/cli-kit/node/git';
|
|
9
9
|
import { resolvePath, relativePath } from '@shopify/cli-kit/node/path';
|
|
10
|
-
import { renderWarning, renderSelectPrompt, renderSuccess, renderTasks } from '@shopify/cli-kit/node/ui';
|
|
10
|
+
import { renderWarning, renderSelectPrompt, renderConfirmationPrompt, renderSuccess, renderTasks } from '@shopify/cli-kit/node/ui';
|
|
11
11
|
import { ciPlatform } from '@shopify/cli-kit/node/context/local';
|
|
12
12
|
import { parseToken, createDeploy } from '@shopify/oxygen-cli/deploy';
|
|
13
|
+
import { findEnvironmentOrThrow, findEnvironmentByBranchOrThrow, orderEnvironmentsBySafety, createEnvironmentCliChoiceLabel } from '../../lib/common.js';
|
|
14
|
+
import { execAsync } from '../../lib/process.js';
|
|
13
15
|
import { commonFlags, flagsToCamelObject } from '../../lib/flags.js';
|
|
14
16
|
import { getOxygenDeploymentData } from '../../lib/get-oxygen-deployment-data.js';
|
|
15
17
|
import { runBuild } from './build.js';
|
|
16
18
|
import { runViteBuild } from './build-vite.js';
|
|
17
19
|
import { getViteConfig } from '../../lib/vite-config.js';
|
|
18
20
|
import { prepareDiffDirectory } from '../../lib/template-diff.js';
|
|
21
|
+
import { hasRemixConfigFile } from '../../lib/remix-config.js';
|
|
22
|
+
import { packageManagers } from '../../lib/package-managers.js';
|
|
19
23
|
|
|
20
24
|
const DEPLOY_OUTPUT_FILE_HANDLE = "h2_deploy_log.json";
|
|
21
25
|
const deploymentLogger = (message, level = "info") => {
|
|
@@ -24,12 +28,12 @@ const deploymentLogger = (message, level = "info") => {
|
|
|
24
28
|
}
|
|
25
29
|
};
|
|
26
30
|
class Deploy extends Command {
|
|
31
|
+
static descriptionWithMarkdown = `Builds and deploys your Hydrogen storefront to Oxygen. Requires an Oxygen deployment token to be set with the \`--token\` flag or an environment variable (\`SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN\`). If the storefront is [linked](https://shopify.dev/docs/api/shopify-cli/hydrogen/hydrogen-link) then the Oxygen deployment token for the linked storefront will be used automatically.`;
|
|
27
32
|
static description = "Builds and deploys a Hydrogen storefront to Oxygen.";
|
|
28
33
|
static flags = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}),
|
|
34
|
+
...commonFlags.entry,
|
|
35
|
+
...commonFlags.env,
|
|
36
|
+
...commonFlags.envBranch,
|
|
33
37
|
"env-file": Flags.string({
|
|
34
38
|
description: "Path to an environment file to override existing environment variables for the deployment.",
|
|
35
39
|
required: false
|
|
@@ -114,7 +118,6 @@ class Deploy extends Command {
|
|
|
114
118
|
return {
|
|
115
119
|
...camelFlags,
|
|
116
120
|
defaultEnvironment: flags.preview,
|
|
117
|
-
environmentTag: flags["env-branch"],
|
|
118
121
|
environmentFile: flags["env-file"],
|
|
119
122
|
path: flags.path ? resolvePath(flags.path) : process.cwd()
|
|
120
123
|
};
|
|
@@ -143,7 +146,8 @@ async function runDeploy(options) {
|
|
|
143
146
|
authBypassToken: generateAuthBypassToken,
|
|
144
147
|
buildCommand,
|
|
145
148
|
defaultEnvironment,
|
|
146
|
-
|
|
149
|
+
env: envHandle,
|
|
150
|
+
envBranch,
|
|
147
151
|
environmentFile,
|
|
148
152
|
force: forceOnUncommitedChanges,
|
|
149
153
|
noVerify,
|
|
@@ -153,7 +157,8 @@ async function runDeploy(options) {
|
|
|
153
157
|
shop,
|
|
154
158
|
metadataUrl,
|
|
155
159
|
metadataUser,
|
|
156
|
-
metadataVersion
|
|
160
|
+
metadataVersion,
|
|
161
|
+
entry: ssrEntry
|
|
157
162
|
} = options;
|
|
158
163
|
let { metadataDescription } = options;
|
|
159
164
|
let isCleanGit = true;
|
|
@@ -164,13 +169,34 @@ async function runDeploy(options) {
|
|
|
164
169
|
isCleanGit = false;
|
|
165
170
|
}
|
|
166
171
|
if (!forceOnUncommitedChanges && !isCleanGit) {
|
|
167
|
-
|
|
172
|
+
let errorMessage = "Uncommitted changes detected";
|
|
173
|
+
let changedFiles = void 0;
|
|
174
|
+
const nextSteps = [
|
|
168
175
|
[
|
|
169
|
-
"Commit your changes before deploying or use the
|
|
176
|
+
"Commit your changes before deploying or use the",
|
|
170
177
|
{ command: "--force" },
|
|
171
|
-
"
|
|
178
|
+
"flag to deploy with uncommitted changes."
|
|
172
179
|
]
|
|
173
|
-
]
|
|
180
|
+
];
|
|
181
|
+
try {
|
|
182
|
+
changedFiles = (await execAsync("git status -s", { cwd: root })).stdout;
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
if (changedFiles) {
|
|
186
|
+
errorMessage += `:
|
|
187
|
+
|
|
188
|
+
${changedFiles.trimEnd()}`;
|
|
189
|
+
packageManagers.forEach(({ name, lockfile, installCommand }) => {
|
|
190
|
+
if (changedFiles.includes(lockfile)) {
|
|
191
|
+
nextSteps.push([
|
|
192
|
+
`If you are using ${name}, try running`,
|
|
193
|
+
{ command: installCommand },
|
|
194
|
+
`to avoid changes to ${lockfile}.`
|
|
195
|
+
]);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
throw new AbortError(errorMessage, null, nextSteps);
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
202
|
const isCI = ciPlatform().isCI;
|
|
@@ -178,7 +204,7 @@ async function runDeploy(options) {
|
|
|
178
204
|
let branch;
|
|
179
205
|
let commitHash;
|
|
180
206
|
let deploymentData;
|
|
181
|
-
let
|
|
207
|
+
let userChosenEnvironmentTag = void 0;
|
|
182
208
|
let gitCommit;
|
|
183
209
|
try {
|
|
184
210
|
gitCommit = await getLatestGitCommit(root);
|
|
@@ -212,6 +238,14 @@ async function runDeploy(options) {
|
|
|
212
238
|
})
|
|
213
239
|
);
|
|
214
240
|
}
|
|
241
|
+
let userProvidedEnvironmentTag = null;
|
|
242
|
+
let isPreview = false;
|
|
243
|
+
if (isCI && envHandle) {
|
|
244
|
+
throw new AbortError(
|
|
245
|
+
"Can't specify an environment handle in CI",
|
|
246
|
+
"Environments are automatically picked up by the current Git branch."
|
|
247
|
+
);
|
|
248
|
+
}
|
|
215
249
|
if (!isCI) {
|
|
216
250
|
deploymentData = await getOxygenDeploymentData({
|
|
217
251
|
root,
|
|
@@ -221,6 +255,20 @@ async function runDeploy(options) {
|
|
|
221
255
|
return;
|
|
222
256
|
}
|
|
223
257
|
token = token || deploymentData.oxygenDeploymentToken;
|
|
258
|
+
if (envHandle) {
|
|
259
|
+
userProvidedEnvironmentTag = findEnvironmentOrThrow(
|
|
260
|
+
deploymentData.environments || [],
|
|
261
|
+
envHandle
|
|
262
|
+
).branch;
|
|
263
|
+
if (userProvidedEnvironmentTag === null) {
|
|
264
|
+
isPreview = true;
|
|
265
|
+
}
|
|
266
|
+
} else if (envBranch) {
|
|
267
|
+
userProvidedEnvironmentTag = findEnvironmentByBranchOrThrow(
|
|
268
|
+
deploymentData.environments || [],
|
|
269
|
+
envBranch
|
|
270
|
+
).branch;
|
|
271
|
+
}
|
|
224
272
|
}
|
|
225
273
|
if (!token) {
|
|
226
274
|
const errMessage = isCI ? [
|
|
@@ -230,20 +278,21 @@ async function runDeploy(options) {
|
|
|
230
278
|
] : `Could not obtain an Oxygen deployment token, please try again or contact Shopify support.`;
|
|
231
279
|
throw new AbortError(errMessage);
|
|
232
280
|
}
|
|
233
|
-
if (!isCI && !defaultEnvironment && !
|
|
281
|
+
if (!isCI && !defaultEnvironment && !envHandle && !envBranch && deploymentData?.environments) {
|
|
234
282
|
if (deploymentData.environments.length > 1) {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
283
|
+
const environments = orderEnvironmentsBySafety(
|
|
284
|
+
deploymentData.environments
|
|
285
|
+
);
|
|
286
|
+
const choices = environments.map(({ name, branch: branch2, handle, type }) => ({
|
|
287
|
+
label: createEnvironmentCliChoiceLabel(name, handle, branch2),
|
|
288
|
+
// The preview environment will never have an associated branch so
|
|
289
|
+
// we're using a custom string here to identify it later in our code.
|
|
290
|
+
// Using a period at the end of the value is an invalid branch name
|
|
291
|
+
// in Git so we can be sure that this won't conflict with a merchant's
|
|
292
|
+
// repository.
|
|
293
|
+
value: type === "PREVIEW" ? "shopify-preview-environment." : branch2
|
|
294
|
+
}));
|
|
295
|
+
userChosenEnvironmentTag = await renderSelectPrompt({
|
|
247
296
|
message: "Select an environment to deploy to",
|
|
248
297
|
choices,
|
|
249
298
|
defaultValue: branch
|
|
@@ -262,18 +311,22 @@ async function runDeploy(options) {
|
|
|
262
311
|
);
|
|
263
312
|
}
|
|
264
313
|
let fallbackEnvironmentTag = branch;
|
|
265
|
-
|
|
266
|
-
if (deploymentEnvironmentTag === "shopify-preview-environment.") {
|
|
314
|
+
if (userChosenEnvironmentTag === "shopify-preview-environment.") {
|
|
267
315
|
fallbackEnvironmentTag = void 0;
|
|
268
|
-
|
|
316
|
+
userChosenEnvironmentTag = void 0;
|
|
269
317
|
isPreview = true;
|
|
270
318
|
}
|
|
271
319
|
let assetsDir = "dist/client";
|
|
272
320
|
let workerDir = "dist/worker";
|
|
273
|
-
const
|
|
274
|
-
if (
|
|
275
|
-
|
|
276
|
-
|
|
321
|
+
const isClassicCompiler = await hasRemixConfigFile(root);
|
|
322
|
+
if (!isClassicCompiler) {
|
|
323
|
+
const viteConfig = await getViteConfig(root, ssrEntry).catch(() => null);
|
|
324
|
+
if (viteConfig) {
|
|
325
|
+
assetsDir = relativePath(root, viteConfig.clientOutDir);
|
|
326
|
+
workerDir = relativePath(root, viteConfig.serverOutDir);
|
|
327
|
+
} else {
|
|
328
|
+
workerDir = "dist/server";
|
|
329
|
+
}
|
|
277
330
|
}
|
|
278
331
|
const config = {
|
|
279
332
|
assetsDir,
|
|
@@ -281,7 +334,7 @@ async function runDeploy(options) {
|
|
|
281
334
|
deploymentUrl,
|
|
282
335
|
defaultEnvironment: defaultEnvironment || isPreview,
|
|
283
336
|
deploymentToken: parseToken(token),
|
|
284
|
-
environmentTag:
|
|
337
|
+
environmentTag: userProvidedEnvironmentTag || userChosenEnvironmentTag || fallbackEnvironmentTag,
|
|
285
338
|
generateAuthBypassToken,
|
|
286
339
|
verificationMaxDuration: 180,
|
|
287
340
|
metadata: {
|
|
@@ -297,6 +350,37 @@ async function runDeploy(options) {
|
|
|
297
350
|
workerDir,
|
|
298
351
|
overriddenEnvironmentVariables
|
|
299
352
|
};
|
|
353
|
+
if (!isCI && (userProvidedEnvironmentTag || userChosenEnvironmentTag || config.defaultEnvironment)) {
|
|
354
|
+
let chosenEnvironment = null;
|
|
355
|
+
if (config.defaultEnvironment) {
|
|
356
|
+
chosenEnvironment = findEnvironmentOrThrow(
|
|
357
|
+
deploymentData.environments,
|
|
358
|
+
"preview"
|
|
359
|
+
);
|
|
360
|
+
} else if (config.environmentTag) {
|
|
361
|
+
chosenEnvironment = findEnvironmentByBranchOrThrow(
|
|
362
|
+
deploymentData.environments,
|
|
363
|
+
config.environmentTag
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
let confirmationMessage = "Creating a deployment";
|
|
367
|
+
if (chosenEnvironment) {
|
|
368
|
+
confirmationMessage += ` against ${createEnvironmentCliChoiceLabel(
|
|
369
|
+
chosenEnvironment.name,
|
|
370
|
+
chosenEnvironment.handle,
|
|
371
|
+
chosenEnvironment.branch
|
|
372
|
+
)}`;
|
|
373
|
+
}
|
|
374
|
+
const confirmPush = await renderConfirmationPrompt({
|
|
375
|
+
confirmationMessage: "Yes, confirm deploy",
|
|
376
|
+
cancellationMessage: "No, cancel deploy",
|
|
377
|
+
message: outputContent`${confirmationMessage}
|
|
378
|
+
|
|
379
|
+
Continue?`.value
|
|
380
|
+
});
|
|
381
|
+
if (!confirmPush)
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
300
384
|
let resolveUpload;
|
|
301
385
|
const uploadPromise = new Promise((resolve) => {
|
|
302
386
|
resolveUpload = resolve;
|
|
@@ -352,13 +436,14 @@ async function runDeploy(options) {
|
|
|
352
436
|
outputInfo(
|
|
353
437
|
outputContent`${colors.whiteBright("Building project...")}`.value
|
|
354
438
|
);
|
|
355
|
-
const build =
|
|
439
|
+
const build = isClassicCompiler ? runBuild : runViteBuild;
|
|
356
440
|
await build({
|
|
357
441
|
directory: root,
|
|
358
442
|
assetPath,
|
|
359
443
|
lockfileCheck,
|
|
360
444
|
sourcemap: true,
|
|
361
|
-
useCodegen: false
|
|
445
|
+
useCodegen: false,
|
|
446
|
+
entry: ssrEntry
|
|
362
447
|
});
|
|
363
448
|
};
|
|
364
449
|
}
|