@shopify/cli-hydrogen 7.1.2 → 8.0.1
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 +10 -1
- package/dist/commands/hydrogen/deploy.js +110 -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 +20 -28
- package/dist/commands/hydrogen/env/pull.js +29 -19
- package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +34 -68
- package/dist/commands/hydrogen/generate/route.js +1 -0
- package/dist/commands/hydrogen/init.js +39 -21
- package/dist/commands/hydrogen/link.js +25 -6
- 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 -23
- 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 +3 -4
- package/dist/generator-templates/assets/vite/vite.config.js +15 -2
- package/dist/generator-templates/starter/CHANGELOG.md +129 -0
- package/dist/generator-templates/starter/README.md +3 -44
- package/dist/generator-templates/starter/app/components/Footer.tsx +1 -1
- package/dist/generator-templates/starter/app/components/Header.tsx +1 -1
- 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/lib/root-data.ts +11 -0
- package/dist/generator-templates/starter/app/root.tsx +4 -20
- 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/blogs.$blogHandle._index.tsx +3 -3
- package/dist/generator-templates/starter/app/routes/cart.tsx +1 -1
- 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 +26 -0
- package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -4
- 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 +99 -0
- package/dist/lib/environment-variables.js +51 -30
- package/dist/lib/file.js +8 -1
- package/dist/lib/flags.js +37 -26
- package/dist/lib/get-oxygen-deployment-data.js +10 -17
- 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 +85 -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/render-errors.js +17 -10
- 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/functions.js +26 -8
- package/dist/lib/transpile/morph/typedefs.js +6 -4
- package/dist/lib/transpile/project.js +8 -4
- package/dist/lib/tunneling.js +44 -0
- package/dist/lib/verify-linked-storefront.js +24 -0
- package/dist/lib/virtual-routes.js +1 -1
- package/dist/lib/vite-config.js +39 -9
- package/oclif.manifest.json +704 -508
- package/package.json +32 -24
- 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 };
|
|
@@ -4,14 +4,18 @@ import Command from '@shopify/cli-kit/node/base-command';
|
|
|
4
4
|
import { outputInfo, outputWarn } from '@shopify/cli-kit/node/output';
|
|
5
5
|
import colors from '@shopify/cli-kit/node/colors';
|
|
6
6
|
import { writeFile } from '@shopify/cli-kit/node/fs';
|
|
7
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
7
8
|
import ansiEscapes from 'ansi-escapes';
|
|
8
|
-
import { getProjectPaths, handleRemixImportFail, getRemixConfig } from '../../../lib/remix-config.js';
|
|
9
|
+
import { getProjectPaths, hasRemixConfigFile, handleRemixImportFail, getRemixConfig } from '../../../lib/remix-config.js';
|
|
9
10
|
import { muteDevLogs, createRemixLogger } from '../../../lib/log.js';
|
|
10
11
|
import { commonFlags, flagsToCamelObject } from '../../../lib/flags.js';
|
|
11
12
|
import { createCpuStartupProfiler } from '../../../lib/cpu-profiler.js';
|
|
12
13
|
|
|
13
14
|
const DEFAULT_OUTPUT_PATH = "startup.cpuprofile";
|
|
14
15
|
class DebugCpu extends Command {
|
|
16
|
+
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.
|
|
17
|
+
|
|
18
|
+
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
19
|
static description = "Builds and profiles the server startup time the app.";
|
|
16
20
|
static flags = {
|
|
17
21
|
...commonFlags.path,
|
|
@@ -40,6 +44,11 @@ async function runDebugCpu({
|
|
|
40
44
|
process.env.NODE_ENV = "production";
|
|
41
45
|
muteDevLogs({ workerReload: false });
|
|
42
46
|
const { root, buildPathWorkerFile } = getProjectPaths(appPath);
|
|
47
|
+
if (!await hasRemixConfigFile(root)) {
|
|
48
|
+
throw new AbortError(
|
|
49
|
+
"No remix.config.js file found. This command is not supported in Vite projects."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
43
52
|
outputInfo(
|
|
44
53
|
"\u23F3\uFE0F Starting profiler for CPU startup... Profile will be written to:\n" + colors.dim(output)
|
|
45
54
|
);
|
|
@@ -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,26 @@ async function runDeploy(options) {
|
|
|
297
350
|
workerDir,
|
|
298
351
|
overriddenEnvironmentVariables
|
|
299
352
|
};
|
|
353
|
+
if (!isCI && !config.defaultEnvironment && (userProvidedEnvironmentTag || userChosenEnvironmentTag)) {
|
|
354
|
+
let chosenEnvironment = findEnvironmentByBranchOrThrow(
|
|
355
|
+
deploymentData.environments,
|
|
356
|
+
config.environmentTag
|
|
357
|
+
);
|
|
358
|
+
let confirmationMessage = `Creating a deployment against ${createEnvironmentCliChoiceLabel(
|
|
359
|
+
chosenEnvironment.name,
|
|
360
|
+
chosenEnvironment.handle,
|
|
361
|
+
chosenEnvironment.branch
|
|
362
|
+
)}`;
|
|
363
|
+
const confirmPush = await renderConfirmationPrompt({
|
|
364
|
+
confirmationMessage: "Yes, confirm deploy",
|
|
365
|
+
cancellationMessage: "No, cancel deploy",
|
|
366
|
+
message: outputContent`${confirmationMessage}
|
|
367
|
+
|
|
368
|
+
Continue?`.value
|
|
369
|
+
});
|
|
370
|
+
if (!confirmPush)
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
300
373
|
let resolveUpload;
|
|
301
374
|
const uploadPromise = new Promise((resolve) => {
|
|
302
375
|
resolveUpload = resolve;
|
|
@@ -352,13 +425,14 @@ async function runDeploy(options) {
|
|
|
352
425
|
outputInfo(
|
|
353
426
|
outputContent`${colors.whiteBright("Building project...")}`.value
|
|
354
427
|
);
|
|
355
|
-
const build =
|
|
428
|
+
const build = isClassicCompiler ? runBuild : runViteBuild;
|
|
356
429
|
await build({
|
|
357
430
|
directory: root,
|
|
358
431
|
assetPath,
|
|
359
432
|
lockfileCheck,
|
|
360
433
|
sourcemap: true,
|
|
361
|
-
useCodegen: false
|
|
434
|
+
useCodegen: false,
|
|
435
|
+
entry: ssrEntry
|
|
362
436
|
});
|
|
363
437
|
};
|
|
364
438
|
}
|