@shopify/cli-hydrogen 8.0.2 → 8.0.4
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 +75 -98
- package/dist/commands/hydrogen/deploy.js +2 -2
- package/dist/commands/hydrogen/dev.js +149 -218
- package/dist/commands/hydrogen/init.js +2 -10
- package/dist/commands/hydrogen/upgrade.js +79 -66
- package/dist/generator-templates/starter/CHANGELOG.md +28 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +2 -14
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +1 -1
- package/dist/generator-templates/starter/package.json +8 -8
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +1 -1
- package/dist/lib/classic-compiler/build.js +132 -0
- package/dist/lib/classic-compiler/dev.js +262 -0
- package/dist/lib/flags.js +1 -1
- package/dist/lib/onboarding/index.js +16 -2
- package/dist/lib/onboarding/setup-template.mocks.js +72 -0
- package/dist/lib/template-diff.js +7 -3
- package/oclif.manifest.json +35 -244
- package/package.json +6 -6
- package/dist/commands/hydrogen/build-vite.js +0 -140
- package/dist/commands/hydrogen/dev-vite.js +0 -228
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { renderFatalError } from '@shopify/cli-kit/node/ui';
|
|
5
|
-
import { resolvePath, relativePath } from '@shopify/cli-kit/node/path';
|
|
6
|
-
import { copyPublicFiles } from './build.js';
|
|
7
|
-
import { getProjectPaths, assertOxygenChecks, handleRemixImportFail, getRemixConfig } from '../../lib/remix-config.js';
|
|
8
|
-
import { setH2OVerbose, isH2Verbose, muteDevLogs, createRemixLogger, enhanceH2Logs } from '../../lib/log.js';
|
|
9
|
-
import { commonFlags, deprecated, flagsToCamelObject, DEFAULT_APP_PORT } from '../../lib/flags.js';
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { setH2OVerbose, isH2Verbose, muteDevLogs, enhanceH2Logs } from '../../lib/log.js';
|
|
3
|
+
import { commonFlags, overrideFlag, deprecated, flagsToCamelObject, DEFAULT_INSPECTOR_PORT, DEFAULT_APP_PORT } from '../../lib/flags.js';
|
|
10
4
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
5
|
+
import colors from '@shopify/cli-kit/node/colors';
|
|
6
|
+
import { resolvePath } from '@shopify/cli-kit/node/path';
|
|
7
|
+
import { collectLog } from '@shopify/cli-kit/node/output';
|
|
8
|
+
import { renderSuccess } from '@shopify/cli-kit/node/ui';
|
|
9
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
11
10
|
import { Flags } from '@oclif/core';
|
|
12
|
-
import { buildAssetsUrl, startMiniOxygen } from '../../lib/mini-oxygen/index.js';
|
|
13
|
-
import { addVirtualRoutes } from '../../lib/virtual-routes.js';
|
|
14
11
|
import { spawnCodegenProcess } from '../../lib/codegen.js';
|
|
15
12
|
import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
|
|
16
|
-
import { setupLiveReload } from '../../lib/live-reload.js';
|
|
17
|
-
import { checkRemixVersions } from '../../lib/remix-version-check.js';
|
|
18
13
|
import { displayDevUpgradeNotice } from './upgrade.js';
|
|
19
|
-
import { findPort } from '../../lib/find-port.js';
|
|
20
14
|
import { prepareDiffDirectory, copyShopifyConfig } from '../../lib/template-diff.js';
|
|
21
|
-
import { getDevConfigInBackground, startTunnelAndPushConfig, isMockShop, notifyIssueWithTunnelAndMockShop } from '../../lib/dev-shared.js';
|
|
15
|
+
import { getDevConfigInBackground, TUNNEL_DOMAIN, startTunnelAndPushConfig, getUtilityBannerlines, getDebugBannerLine, isMockShop, notifyIssueWithTunnelAndMockShop } from '../../lib/dev-shared.js';
|
|
22
16
|
import { getCliCommand } from '../../lib/shell.js';
|
|
23
|
-
import {
|
|
17
|
+
import { findPort } from '../../lib/find-port.js';
|
|
18
|
+
import { logRequestLine } from '../../lib/mini-oxygen/common.js';
|
|
19
|
+
import { hasViteConfig, findHydrogenPlugin, findOxygenPlugin } from '../../lib/vite-config.js';
|
|
20
|
+
import { runClassicCompilerDev } from '../../lib/classic-compiler/dev.js';
|
|
24
21
|
|
|
25
|
-
const LOG_REBUILDING = "\u{1F9F1} Rebuilding...";
|
|
26
|
-
const LOG_REBUILT = "\u{1F680} Rebuilt";
|
|
27
22
|
class Dev extends Command {
|
|
28
23
|
static descriptionWithMarkdown = `Runs a Hydrogen storefront in a local runtime that emulates an Oxygen worker for development.
|
|
29
24
|
|
|
@@ -31,11 +26,11 @@ class Dev extends Command {
|
|
|
31
26
|
static description = "Runs Hydrogen storefront in an Oxygen worker for development.";
|
|
32
27
|
static flags = {
|
|
33
28
|
...commonFlags.path,
|
|
34
|
-
...commonFlags.
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
...commonFlags.entry,
|
|
30
|
+
...overrideFlag(commonFlags.port, {
|
|
31
|
+
port: { default: void 0, required: false }
|
|
32
|
+
}),
|
|
37
33
|
...commonFlags.codegen,
|
|
38
|
-
...commonFlags.sourcemap,
|
|
39
34
|
"disable-virtual-routes": Flags.boolean({
|
|
40
35
|
description: "Disable rendering fallback routes when a route file doesn't exist.",
|
|
41
36
|
env: "SHOPIFY_HYDROGEN_FLAG_DISABLE_VIRTUAL_ROUTES",
|
|
@@ -52,7 +47,24 @@ class Dev extends Command {
|
|
|
52
47
|
}),
|
|
53
48
|
...commonFlags.diff,
|
|
54
49
|
...commonFlags.customerAccountPush,
|
|
55
|
-
...commonFlags.verbose
|
|
50
|
+
...commonFlags.verbose,
|
|
51
|
+
host: Flags.boolean({
|
|
52
|
+
description: "Expose the server to the local network",
|
|
53
|
+
default: false,
|
|
54
|
+
required: false
|
|
55
|
+
}),
|
|
56
|
+
// For the classic compiler:
|
|
57
|
+
worker: deprecated("--worker", { isBoolean: true }),
|
|
58
|
+
...overrideFlag(commonFlags.legacyRuntime, {
|
|
59
|
+
"legacy-runtime": {
|
|
60
|
+
description: "[Classic Remix Compiler] " + commonFlags.legacyRuntime["legacy-runtime"].description
|
|
61
|
+
}
|
|
62
|
+
}),
|
|
63
|
+
...overrideFlag(commonFlags.sourcemap, {
|
|
64
|
+
sourcemap: {
|
|
65
|
+
description: "[Classic Remix Compiler] " + commonFlags.sourcemap.sourcemap.description
|
|
66
|
+
}
|
|
67
|
+
})
|
|
56
68
|
};
|
|
57
69
|
async run() {
|
|
58
70
|
const { flags } = await this.parse(Dev);
|
|
@@ -67,9 +79,7 @@ class Dev extends Command {
|
|
|
67
79
|
path: directory,
|
|
68
80
|
cliConfig: this.config
|
|
69
81
|
};
|
|
70
|
-
const { close } = await hasViteConfig(directory
|
|
71
|
-
({ runViteDev }) => runViteDev(devParams)
|
|
72
|
-
) : await runDev(devParams);
|
|
82
|
+
const { close } = await hasViteConfig(directory) ? await runDev(devParams) : await runClassicCompilerDev(devParams);
|
|
73
83
|
let closingPromise;
|
|
74
84
|
const processExit = process.exit;
|
|
75
85
|
process.exit = async (code) => {
|
|
@@ -83,20 +93,20 @@ class Dev extends Command {
|
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
95
|
async function runDev({
|
|
96
|
+
entry: ssrEntry,
|
|
86
97
|
port: appPort,
|
|
87
98
|
path: appPath,
|
|
99
|
+
host,
|
|
88
100
|
codegen: useCodegen = false,
|
|
89
|
-
legacyRuntime = false,
|
|
90
101
|
codegenConfigPath,
|
|
91
102
|
disableVirtualRoutes,
|
|
92
|
-
env: envHandle,
|
|
93
103
|
envBranch,
|
|
104
|
+
env: envHandle,
|
|
94
105
|
debug = false,
|
|
95
|
-
sourcemap = true,
|
|
96
106
|
disableVersionCheck = false,
|
|
97
107
|
inspectorPort,
|
|
108
|
+
isLocalDev = false,
|
|
98
109
|
customerAccountPush: customerAccountPushFlag = false,
|
|
99
|
-
shouldLiveReload = true,
|
|
100
110
|
cliConfig,
|
|
101
111
|
verbose
|
|
102
112
|
}) {
|
|
@@ -106,217 +116,138 @@ async function runDev({
|
|
|
106
116
|
setH2OVerbose();
|
|
107
117
|
if (!isH2Verbose())
|
|
108
118
|
muteDevLogs();
|
|
109
|
-
const
|
|
110
|
-
const copyFilesPromise = copyPublicFiles(publicPath, buildPathClient);
|
|
119
|
+
const root = appPath ?? process.cwd();
|
|
111
120
|
const cliCommandPromise = getCliCommand(root);
|
|
112
|
-
const reloadConfig = async () => {
|
|
113
|
-
const config = await getRemixConfig(root);
|
|
114
|
-
return disableVirtualRoutes ? config : addVirtualRoutes(config).catch((error) => {
|
|
115
|
-
outputDebug(
|
|
116
|
-
"Could not add virtual routes: " + (error?.stack ?? error?.message ?? error)
|
|
117
|
-
);
|
|
118
|
-
return config;
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
const getFilePaths = (file) => {
|
|
122
|
-
const fileRelative = relativePath(root, file);
|
|
123
|
-
return [fileRelative, resolvePath(root, fileRelative)];
|
|
124
|
-
};
|
|
125
|
-
const serverBundleExists = () => fileExists(buildPathWorkerFile);
|
|
126
|
-
if (!appPort) {
|
|
127
|
-
appPort = await findPort(DEFAULT_APP_PORT);
|
|
128
|
-
}
|
|
129
|
-
const assetsPort = legacyRuntime ? 0 : await findPort(appPort + 100);
|
|
130
|
-
if (assetsPort) {
|
|
131
|
-
process.env.HYDROGEN_ASSET_BASE_URL = await buildAssetsUrl(assetsPort);
|
|
132
|
-
}
|
|
133
121
|
const backgroundPromise = getDevConfigInBackground(
|
|
134
122
|
root,
|
|
135
123
|
customerAccountPushFlag
|
|
136
124
|
);
|
|
137
|
-
const tunnelPromise = cliConfig && backgroundPromise.then(({ customerAccountPush, storefrontId }) => {
|
|
138
|
-
if (customerAccountPush) {
|
|
139
|
-
return startTunnelAndPushConfig(
|
|
140
|
-
root,
|
|
141
|
-
cliConfig,
|
|
142
|
-
appPort,
|
|
143
|
-
storefrontId
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
const remixConfig = await reloadConfig();
|
|
148
|
-
assertOxygenChecks(remixConfig);
|
|
149
125
|
const envPromise = backgroundPromise.then(
|
|
150
126
|
({ fetchRemote, localVariables }) => getAllEnvironmentVariables({
|
|
151
127
|
root,
|
|
152
|
-
fetchRemote,
|
|
153
128
|
envBranch,
|
|
154
129
|
envHandle,
|
|
130
|
+
fetchRemote,
|
|
155
131
|
localVariables
|
|
156
132
|
})
|
|
157
133
|
);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
import('@remix-run/dev/dist/compiler/fileWatchCache.js')
|
|
161
|
-
]).catch(handleRemixImportFail);
|
|
162
|
-
let isInitialBuild = true;
|
|
163
|
-
let initialBuildDurationMs = 0;
|
|
164
|
-
let initialBuildStartTimeMs = Date.now();
|
|
165
|
-
const liveReload = shouldLiveReload ? await setupLiveReload(remixConfig.dev?.port ?? 8002) : void 0;
|
|
166
|
-
let miniOxygen;
|
|
167
|
-
let codegenProcess;
|
|
168
|
-
async function safeStartMiniOxygen() {
|
|
169
|
-
if (miniOxygen)
|
|
170
|
-
return;
|
|
171
|
-
const { allVariables, logInjectedVariables } = await envPromise;
|
|
172
|
-
miniOxygen = await startMiniOxygen(
|
|
173
|
-
{
|
|
174
|
-
root,
|
|
175
|
-
debug,
|
|
176
|
-
appPort,
|
|
177
|
-
assetsPort,
|
|
178
|
-
inspectorPort,
|
|
179
|
-
watch: !liveReload,
|
|
180
|
-
buildPathWorkerFile,
|
|
181
|
-
buildPathClient,
|
|
182
|
-
env: allVariables
|
|
183
|
-
},
|
|
184
|
-
legacyRuntime
|
|
185
|
-
);
|
|
186
|
-
logInjectedVariables();
|
|
187
|
-
const host = (await tunnelPromise)?.host ?? miniOxygen.listeningAt;
|
|
188
|
-
const cliCommand = await cliCommandPromise;
|
|
189
|
-
enhanceH2Logs({ host, cliCommand, ...remixConfig });
|
|
190
|
-
const { storefrontTitle } = await backgroundPromise;
|
|
191
|
-
miniOxygen.showBanner({
|
|
192
|
-
appName: storefrontTitle,
|
|
193
|
-
headlinePrefix: initialBuildDurationMs > 0 ? `Initial build: ${initialBuildDurationMs}ms
|
|
194
|
-
` : "",
|
|
195
|
-
host
|
|
196
|
-
});
|
|
197
|
-
if (useCodegen) {
|
|
198
|
-
codegenProcess = spawnCodegenProcess({
|
|
199
|
-
...remixConfig,
|
|
200
|
-
configFilePath: codegenConfigPath
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
checkRemixVersions();
|
|
204
|
-
if (!disableVersionCheck) {
|
|
205
|
-
displayDevUpgradeNotice({ targetPath: appPath });
|
|
206
|
-
}
|
|
207
|
-
if (customerAccountPushFlag && isMockShop(allVariables)) {
|
|
208
|
-
notifyIssueWithTunnelAndMockShop(cliCommand);
|
|
209
|
-
}
|
|
134
|
+
if (debug && !inspectorPort) {
|
|
135
|
+
inspectorPort = await findPort(DEFAULT_INSPECTOR_PORT);
|
|
210
136
|
}
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
liveReload?.onBuildStart(ctx);
|
|
231
|
-
},
|
|
232
|
-
onBuildManifest: liveReload?.onBuildManifest,
|
|
233
|
-
async onBuildFinish(context, duration, succeeded) {
|
|
234
|
-
if (isInitialBuild) {
|
|
235
|
-
await copyFilesPromise;
|
|
236
|
-
initialBuildDurationMs = Date.now() - initialBuildStartTimeMs;
|
|
237
|
-
isInitialBuild = false;
|
|
238
|
-
} else if (!skipRebuildLogs) {
|
|
239
|
-
skipRebuildLogs = false;
|
|
240
|
-
console.timeEnd(LOG_REBUILT);
|
|
241
|
-
if (!miniOxygen)
|
|
242
|
-
console.log("");
|
|
243
|
-
}
|
|
244
|
-
if (!miniOxygen && !await serverBundleExists()) {
|
|
245
|
-
return renderFatalError({
|
|
246
|
-
name: "BuildError",
|
|
247
|
-
type: 0,
|
|
248
|
-
message: "MiniOxygen cannot start because the server bundle has not been generated.",
|
|
249
|
-
skipOclifErrorHandling: true,
|
|
250
|
-
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."
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
if (succeeded) {
|
|
254
|
-
if (!miniOxygen) {
|
|
255
|
-
await safeStartMiniOxygen();
|
|
256
|
-
} else if (liveReload) {
|
|
257
|
-
await miniOxygen.reload();
|
|
258
|
-
}
|
|
259
|
-
liveReload?.onAppReady(context);
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
async onFileCreated(file) {
|
|
263
|
-
const [relative, absolute] = getFilePaths(file);
|
|
264
|
-
outputInfo(`
|
|
265
|
-
\u{1F4C4} File created: ${relative}`);
|
|
266
|
-
if (absolute.startsWith(publicPath)) {
|
|
267
|
-
await copyPublicFiles(
|
|
268
|
-
absolute,
|
|
269
|
-
absolute.replace(publicPath, buildPathClient)
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
async onFileChanged(file) {
|
|
274
|
-
fileWatchCache.invalidateFile(file);
|
|
275
|
-
const [relative, absolute] = getFilePaths(file);
|
|
276
|
-
outputInfo(`
|
|
277
|
-
\u{1F4C4} File changed: ${relative}`);
|
|
278
|
-
if (relative.endsWith(".env")) {
|
|
279
|
-
skipRebuildLogs = true;
|
|
280
|
-
const { fetchRemote } = await backgroundPromise;
|
|
281
|
-
const { allVariables, logInjectedVariables } = await getAllEnvironmentVariables({
|
|
282
|
-
root,
|
|
283
|
-
fetchRemote,
|
|
284
|
-
envBranch,
|
|
285
|
-
envHandle
|
|
137
|
+
const vite = await import('vite');
|
|
138
|
+
const fs = isLocalDev ? { allow: [root, fileURLToPath(new URL("../../../../", import.meta.url))] } : void 0;
|
|
139
|
+
const customLogger = vite.createLogger();
|
|
140
|
+
if (process.env.SHOPIFY_UNIT_TEST) {
|
|
141
|
+
customLogger.info = (msg) => collectLog("info", msg);
|
|
142
|
+
customLogger.warn = (msg) => collectLog("warn", msg);
|
|
143
|
+
customLogger.error = (msg) => collectLog("error", msg);
|
|
144
|
+
}
|
|
145
|
+
const viteServer = await vite.createServer({
|
|
146
|
+
root,
|
|
147
|
+
customLogger,
|
|
148
|
+
clearScreen: false,
|
|
149
|
+
server: { fs, host: host ? true : void 0 },
|
|
150
|
+
plugins: [
|
|
151
|
+
{
|
|
152
|
+
name: "hydrogen:cli",
|
|
153
|
+
configResolved(config) {
|
|
154
|
+
findHydrogenPlugin(config)?.api?.registerPluginOptions({
|
|
155
|
+
disableVirtualRoutes
|
|
286
156
|
});
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
157
|
+
findOxygenPlugin(config)?.api?.registerPluginOptions({
|
|
158
|
+
debug,
|
|
159
|
+
entry: ssrEntry,
|
|
160
|
+
envPromise: envPromise.then(({ allVariables: allVariables2 }) => allVariables2),
|
|
161
|
+
inspectorPort,
|
|
162
|
+
logRequestLine
|
|
290
163
|
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
await fs.unlink(absolute.replace(publicPath, buildPathClient));
|
|
164
|
+
},
|
|
165
|
+
configureServer: (viteDevServer) => {
|
|
166
|
+
if (customerAccountPushFlag) {
|
|
167
|
+
viteDevServer.middlewares.use((req, res, next) => {
|
|
168
|
+
const host2 = req.headers.host;
|
|
169
|
+
if (host2?.includes(TUNNEL_DOMAIN.ORIGINAL)) {
|
|
170
|
+
req.headers.host = host2.replace(
|
|
171
|
+
TUNNEL_DOMAIN.ORIGINAL,
|
|
172
|
+
TUNNEL_DOMAIN.REBRANDED
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
next();
|
|
176
|
+
});
|
|
177
|
+
}
|
|
306
178
|
}
|
|
307
179
|
}
|
|
308
|
-
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
const h2Plugin = findHydrogenPlugin(viteServer.config);
|
|
183
|
+
if (!h2Plugin) {
|
|
184
|
+
await viteServer.close();
|
|
185
|
+
throw new AbortError(
|
|
186
|
+
"Hydrogen plugin not found.",
|
|
187
|
+
"Add `hydrogen()` plugin to your Vite config."
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const h2PluginOptions = h2Plugin.api?.getPluginOptions?.();
|
|
191
|
+
const codegenProcess = useCodegen ? spawnCodegenProcess({
|
|
192
|
+
rootDirectory: root,
|
|
193
|
+
configFilePath: codegenConfigPath,
|
|
194
|
+
appDirectory: h2PluginOptions?.remixConfig?.appDirectory
|
|
195
|
+
}) : void 0;
|
|
196
|
+
process.on("unhandledRejection", (err) => {
|
|
197
|
+
console.log("Unhandled Rejection: ", err);
|
|
198
|
+
});
|
|
199
|
+
const publicPort = appPort ?? viteServer.config.server.port ?? DEFAULT_APP_PORT;
|
|
200
|
+
const [tunnel, cliCommand] = await Promise.all([
|
|
201
|
+
backgroundPromise.then(
|
|
202
|
+
({ customerAccountPush, storefrontId }) => customerAccountPush ? startTunnelAndPushConfig(root, cliConfig, publicPort, storefrontId) : void 0
|
|
203
|
+
),
|
|
204
|
+
cliCommandPromise,
|
|
205
|
+
viteServer.listen(publicPort)
|
|
206
|
+
]);
|
|
207
|
+
const publicUrl = new URL(
|
|
208
|
+
viteServer.resolvedUrls.local[0] ?? viteServer.resolvedUrls.network[0]
|
|
309
209
|
);
|
|
210
|
+
const finalHost = tunnel?.host || publicUrl.toString() || publicUrl.origin;
|
|
211
|
+
enhanceH2Logs({
|
|
212
|
+
rootDirectory: root,
|
|
213
|
+
host: finalHost,
|
|
214
|
+
cliCommand
|
|
215
|
+
});
|
|
216
|
+
const { logInjectedVariables, allVariables } = await envPromise;
|
|
217
|
+
logInjectedVariables();
|
|
218
|
+
console.log("");
|
|
219
|
+
viteServer.printUrls();
|
|
220
|
+
viteServer.bindCLIShortcuts({ print: true });
|
|
221
|
+
console.log("\n");
|
|
222
|
+
const customSections = [];
|
|
223
|
+
if (!h2PluginOptions?.disableVirtualRoutes) {
|
|
224
|
+
customSections.push({ body: getUtilityBannerlines(finalHost) });
|
|
225
|
+
}
|
|
226
|
+
if (debug && inspectorPort) {
|
|
227
|
+
customSections.push({
|
|
228
|
+
body: { warn: getDebugBannerLine(inspectorPort) }
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
const { storefrontTitle } = await backgroundPromise;
|
|
232
|
+
renderSuccess({
|
|
233
|
+
body: [
|
|
234
|
+
`View ${storefrontTitle ? colors.cyan(storefrontTitle) : "Hydrogen"} app:`,
|
|
235
|
+
{ link: { url: finalHost } }
|
|
236
|
+
],
|
|
237
|
+
customSections
|
|
238
|
+
});
|
|
239
|
+
if (!disableVersionCheck) {
|
|
240
|
+
displayDevUpgradeNotice({ targetPath: root });
|
|
241
|
+
}
|
|
242
|
+
if (customerAccountPushFlag && isMockShop(allVariables)) {
|
|
243
|
+
notifyIssueWithTunnelAndMockShop(cliCommand);
|
|
244
|
+
}
|
|
310
245
|
return {
|
|
311
|
-
getUrl: () =>
|
|
246
|
+
getUrl: () => finalHost,
|
|
312
247
|
async close() {
|
|
313
248
|
codegenProcess?.removeAllListeners("close");
|
|
314
249
|
codegenProcess?.kill("SIGINT");
|
|
315
|
-
await Promise.allSettled([
|
|
316
|
-
closeWatcher(),
|
|
317
|
-
miniOxygen?.close(),
|
|
318
|
-
Promise.resolve(tunnelPromise).then((tunnel) => tunnel?.cleanup?.())
|
|
319
|
-
]);
|
|
250
|
+
await Promise.allSettled([viteServer.close(), tunnel?.cleanup?.()]);
|
|
320
251
|
}
|
|
321
252
|
};
|
|
322
253
|
}
|
|
@@ -3,12 +3,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
import { packageManagerFromUserAgent } from '@shopify/cli-kit/node/node-package-manager';
|
|
4
4
|
import { Flags } from '@oclif/core';
|
|
5
5
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
6
|
-
import { AbortController } from '@shopify/cli-kit/node/abort';
|
|
7
6
|
import { commonFlags, flagsToCamelObject, parseProcessFlags } from '../../lib/flags.js';
|
|
8
7
|
import { checkHydrogenVersion } from '../../lib/check-version.js';
|
|
9
8
|
import { I18N_CHOICES } from '../../lib/setups/i18n/index.js';
|
|
10
9
|
import { supressNodeExperimentalWarnings } from '../../lib/process.js';
|
|
11
|
-
import {
|
|
10
|
+
import { setupTemplate } from '../../lib/onboarding/index.js';
|
|
12
11
|
import { LANGUAGES } from '../../lib/onboarding/common.js';
|
|
13
12
|
|
|
14
13
|
const FLAG_MAP = { f: "force" };
|
|
@@ -103,14 +102,7 @@ async function runInit({
|
|
|
103
102
|
packageManager === "unknown" ? "" : `Please use the latest version with \`${packageManager} create @shopify/hydrogen@latest\``
|
|
104
103
|
);
|
|
105
104
|
}
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
const template = options.template;
|
|
109
|
-
return template ? await setupRemoteTemplate({ ...options, template }, controller) : await setupLocalStarterTemplate(options, controller);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
controller.abort();
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
105
|
+
return setupTemplate(options);
|
|
114
106
|
}
|
|
115
107
|
|
|
116
108
|
export { Init as default, runInit };
|
|
@@ -6,7 +6,7 @@ import cliTruncate from 'cli-truncate';
|
|
|
6
6
|
import { Flags } from '@oclif/core';
|
|
7
7
|
import { ensureInsideGitDirectory, isClean } from '@shopify/cli-kit/node/git';
|
|
8
8
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
9
|
-
import { renderSuccess, renderInfo, renderConfirmationPrompt, renderTasks, renderSelectPrompt } from '@shopify/cli-kit/node/ui';
|
|
9
|
+
import { renderSuccess, renderInfo, renderConfirmationPrompt, renderTasks, renderSelectPrompt, renderWarning } from '@shopify/cli-kit/node/ui';
|
|
10
10
|
import { readFile, isDirectory, mkdir, fileExists, touchFile, removeFile, writeFile } from '@shopify/cli-kit/node/fs';
|
|
11
11
|
import { installNodeModules, getPackageManager, getDependencies } from '@shopify/cli-kit/node/node-package-manager';
|
|
12
12
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
@@ -174,7 +174,7 @@ async function getChangelog() {
|
|
|
174
174
|
} catch {
|
|
175
175
|
}
|
|
176
176
|
throw new AbortError(
|
|
177
|
-
"Failed to fetch changelog",
|
|
177
|
+
"Failed to fetch Hydrogen changelog",
|
|
178
178
|
"Ensure you have internet connection and try again"
|
|
179
179
|
);
|
|
180
180
|
}
|
|
@@ -182,7 +182,10 @@ function hasOutdatedDependencies({
|
|
|
182
182
|
release,
|
|
183
183
|
currentDependencies
|
|
184
184
|
}) {
|
|
185
|
-
return Object.entries(
|
|
185
|
+
return Object.entries({
|
|
186
|
+
...release.dependencies,
|
|
187
|
+
...release.devDependencies
|
|
188
|
+
}).some(([name, version]) => {
|
|
186
189
|
const currentDependencyVersion = currentDependencies?.[name];
|
|
187
190
|
if (!currentDependencyVersion)
|
|
188
191
|
return false;
|
|
@@ -653,71 +656,81 @@ Do you want to overwrite it?`,
|
|
|
653
656
|
async function displayDevUpgradeNotice({
|
|
654
657
|
targetPath
|
|
655
658
|
}) {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
659
|
+
try {
|
|
660
|
+
const appPath = targetPath ? path.resolve(targetPath) : process.cwd();
|
|
661
|
+
const { currentVersion } = await getHydrogenVersion({ appPath });
|
|
662
|
+
const isPrerelease = semver.prerelease(currentVersion);
|
|
663
|
+
if (isPrerelease || /^[a-z]+$/i.test(currentVersion)) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
const changelog = await getChangelog();
|
|
667
|
+
const { availableUpgrades, uniqueAvailableUpgrades } = getAvailableUpgrades({
|
|
668
|
+
releases: changelog.releases,
|
|
669
|
+
currentVersion
|
|
670
|
+
});
|
|
671
|
+
if (availableUpgrades.length === 0 || !availableUpgrades[0]?.version) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const pinnedLatestVersion = getAbsoluteVersion(
|
|
675
|
+
availableUpgrades[0].version
|
|
676
|
+
);
|
|
677
|
+
const pinnedCurrentVersion = getAbsoluteVersion(currentVersion);
|
|
678
|
+
const currentReleaseIndex = changelog.releases.findIndex((release) => {
|
|
679
|
+
const pinnedReleaseVersion = getAbsoluteVersion(release.version);
|
|
680
|
+
return pinnedReleaseVersion === pinnedCurrentVersion;
|
|
681
|
+
});
|
|
682
|
+
const uniqueNextReleases = changelog.releases.slice(0, currentReleaseIndex).reverse().reduce((acc, release) => {
|
|
683
|
+
if (acc[release.version])
|
|
684
|
+
return acc;
|
|
685
|
+
acc[release.version] = release;
|
|
678
686
|
return acc;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
].flat().filter(Boolean)
|
|
687
|
+
}, {});
|
|
688
|
+
const nextReleases = Object.keys(uniqueNextReleases).length ? Object.entries(uniqueNextReleases).map(([version, release]) => {
|
|
689
|
+
return `${version} - ${release.title}`;
|
|
690
|
+
}).slice(0, 5) : [];
|
|
691
|
+
let headline = Object.keys(uniqueAvailableUpgrades).length > 1 ? `There are ${Object.keys(uniqueAvailableUpgrades).length} new @shopify/hydrogen versions available.` : `There's a new @shopify/hydrogen version available.`;
|
|
692
|
+
const cliCommand = await getCliCommand();
|
|
693
|
+
renderInfo({
|
|
694
|
+
headline,
|
|
695
|
+
body: [`Current: ${currentVersion} | Latest: ${pinnedLatestVersion}`],
|
|
696
|
+
//@ts-ignore will always be an array
|
|
697
|
+
customSections: nextReleases.length ? [
|
|
698
|
+
{
|
|
699
|
+
title: `The next ${nextReleases.length} version(s) include`,
|
|
700
|
+
body: [
|
|
701
|
+
{
|
|
702
|
+
list: {
|
|
703
|
+
items: [
|
|
704
|
+
...nextReleases,
|
|
705
|
+
availableUpgrades.length > 5 && `...more`
|
|
706
|
+
].flat().filter(Boolean)
|
|
707
|
+
}
|
|
701
708
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
709
|
+
].filter(Boolean)
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
title: "Next steps",
|
|
713
|
+
body: [
|
|
714
|
+
{
|
|
715
|
+
list: {
|
|
716
|
+
items: [
|
|
717
|
+
`Run \`${cliCommand} upgrade\` or \`${cliCommand} upgrade --version XXXX.X.XX\``,
|
|
718
|
+
,
|
|
719
|
+
`Read release notes at https://hydrogen.shopify.dev/releases`
|
|
720
|
+
]
|
|
721
|
+
}
|
|
715
722
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
})
|
|
723
|
+
]
|
|
724
|
+
}
|
|
725
|
+
] : []
|
|
726
|
+
});
|
|
727
|
+
} catch (error) {
|
|
728
|
+
const abortError = error;
|
|
729
|
+
renderWarning({
|
|
730
|
+
headline: abortError.message,
|
|
731
|
+
body: abortError.tryMessage ?? void 0
|
|
732
|
+
});
|
|
733
|
+
}
|
|
721
734
|
}
|
|
722
735
|
|
|
723
|
-
export { buildUpgradeCommandArgs, Upgrade as default, displayConfirmation, displayDevUpgradeNotice, getAbsoluteVersion, getAvailableUpgrades, getChangelog, getCummulativeRelease, getHydrogenVersion, getSelectedRelease,
|
|
736
|
+
export { buildUpgradeCommandArgs, Upgrade as default, displayConfirmation, displayDevUpgradeNotice, getAbsoluteVersion, getAvailableUpgrades, getChangelog, getCummulativeRelease, getHydrogenVersion, getSelectedRelease, isUpgradeableRelease, runUpgrade, upgradeNodeModules };
|