@shopify/cli-hydrogen 12.0.0 → 12.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/assets/hydrogen/routes/locale-check.ts +3 -3
- package/dist/assets/hydrogen/starter/.graphqlrc.ts +4 -2
- package/dist/assets/hydrogen/starter/CHANGELOG.md +278 -0
- package/dist/assets/hydrogen/starter/app/components/Aside.tsx +4 -2
- package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +67 -38
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +49 -8
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +133 -57
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +3 -3
- package/dist/assets/hydrogen/starter/app/components/MockShopNotice.tsx +20 -0
- package/dist/assets/hydrogen/starter/app/components/PaginatedResourceSection.tsx +24 -4
- package/dist/assets/hydrogen/starter/app/components/ProductPrice.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/entry.client.tsx +2 -3
- package/dist/assets/hydrogen/starter/app/lib/context.ts +5 -0
- package/dist/assets/hydrogen/starter/app/lib/fragments.ts +8 -0
- package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +14 -53
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +15 -9
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +14 -14
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.tsx +4 -7
- package/dist/assets/hydrogen/starter/app/routes/account_.login.tsx +10 -0
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +2 -9
- package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +1 -4
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +3 -11
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +1 -3
- package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +2 -8
- package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +1 -4
- package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +2 -9
- package/dist/assets/hydrogen/starter/app/routes/search.tsx +18 -12
- package/dist/assets/hydrogen/starter/app/styles/app.css +72 -1
- package/dist/assets/hydrogen/starter/eslint.config.js +1 -0
- package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +3 -3
- package/dist/assets/hydrogen/starter/guides/search/search.md +1 -1
- package/dist/assets/hydrogen/starter/package.json +16 -16
- package/dist/assets/hydrogen/starter/server.ts +5 -7
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +89 -11
- package/dist/assets/hydrogen/starter/vite.config.ts +10 -4
- package/dist/assets/hydrogen/vite/package.json +1 -2
- package/dist/assets/hydrogen/vite/vite.config.js +4 -3
- package/dist/commands/hydrogen/deploy.js +19 -13
- package/dist/commands/hydrogen/dev.js +6 -6
- package/dist/commands/hydrogen/generate/route.js +1 -1
- package/dist/commands/hydrogen/init.d.ts +2 -4
- package/dist/commands/hydrogen/init.js +2 -8
- package/dist/commands/hydrogen/preview.js +1 -1
- package/dist/commands/hydrogen/setup/css.js +1 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -1
- package/dist/commands/hydrogen/setup/vite.js +1 -1
- package/dist/commands/hydrogen/setup.js +31 -33
- package/dist/commands/hydrogen/upgrade.js +173 -39
- package/dist/lib/build.js +4 -5
- package/dist/lib/bundle/vite-plugin.js +7 -21
- package/dist/lib/check-lockfile.js +16 -7
- package/dist/lib/codegen.js +2 -2
- package/dist/lib/format-code.js +3 -3
- package/dist/lib/graphql/admin/client.js +48 -23
- package/dist/lib/import-utils.js +20 -4
- package/dist/lib/mini-oxygen/workerd.js +3 -5
- package/dist/lib/onboarding/common.js +21 -26
- package/dist/lib/onboarding/local.js +46 -59
- package/dist/lib/package-managers.js +2 -0
- package/dist/lib/patch-cli.js +198 -0
- package/dist/lib/setups/routes/generate.js +5 -3
- package/dist/lib/template-pack.js +93 -0
- package/dist/lib/transpile/morph/functions.js +1 -1
- package/dist/lib/transpile/morph/typedefs.js +2 -3
- package/dist/lib/upgrade-e2e-utils.js +50 -0
- package/oclif.manifest.json +7 -15
- package/package.json +22 -19
- package/dist/assets/hydrogen/starter/app/routes/api.$version.[graphql.json].tsx +0 -14
- package/dist/lib/react-router-version-check.js +0 -82
|
@@ -6,7 +6,7 @@ import { ensureInsideGitDirectory, isClean } from '@shopify/cli-kit/node/git';
|
|
|
6
6
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
7
7
|
import { renderSuccess, renderInfo, renderConfirmationPrompt, renderTasks, renderSelectPrompt, renderWarning } from '@shopify/cli-kit/node/ui';
|
|
8
8
|
import { isDirectory, readFile, mkdir, fileExists, touchFile, removeFile, writeFile } from '@shopify/cli-kit/node/fs';
|
|
9
|
-
import { getPackageManager, getDependencies
|
|
9
|
+
import { getPackageManager, getDependencies } from '@shopify/cli-kit/node/node-package-manager';
|
|
10
10
|
import { exec } from '@shopify/cli-kit/node/system';
|
|
11
11
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
12
12
|
import { resolvePath, joinPath, dirname } from '@shopify/cli-kit/node/path';
|
|
@@ -17,6 +17,9 @@ import { isHydrogenMonorepo, hydrogenPackagesPath } from '../../lib/build.js';
|
|
|
17
17
|
import { isCI } from '../../lib/is-ci.js';
|
|
18
18
|
import { fetch } from '@shopify/cli-kit/node/http';
|
|
19
19
|
|
|
20
|
+
function getAllRemovedPackages(release) {
|
|
21
|
+
return [...release.removeDependencies, ...release.removeDevDependencies];
|
|
22
|
+
}
|
|
20
23
|
const INSTRUCTIONS_FOLDER = ".hydrogen";
|
|
21
24
|
class Upgrade extends Command {
|
|
22
25
|
static descriptionWithMarkdown = "Upgrade Hydrogen project dependencies, preview features, fixes and breaking changes. The command also generates an instruction file for each upgrade.";
|
|
@@ -106,7 +109,7 @@ async function runUpgrade({
|
|
|
106
109
|
availableUpgrades,
|
|
107
110
|
currentDependencies
|
|
108
111
|
});
|
|
109
|
-
cumulativeRelease =
|
|
112
|
+
cumulativeRelease = getCumulativeRelease({
|
|
110
113
|
availableUpgrades,
|
|
111
114
|
currentVersion,
|
|
112
115
|
currentDependencies,
|
|
@@ -128,7 +131,11 @@ async function runUpgrade({
|
|
|
128
131
|
appPath,
|
|
129
132
|
selectedRelease,
|
|
130
133
|
currentDependencies,
|
|
131
|
-
targetVersion
|
|
134
|
+
targetVersion,
|
|
135
|
+
cumulativeRemoveDependencies: cumulativeRelease.removeDependencies,
|
|
136
|
+
cumulativeRemoveDevDependencies: cumulativeRelease.removeDevDependencies,
|
|
137
|
+
cumulativeDependencies: cumulativeRelease.dependencies,
|
|
138
|
+
cumulativeDevDependencies: cumulativeRelease.devDependencies
|
|
132
139
|
});
|
|
133
140
|
await validateUpgrade({
|
|
134
141
|
appPath,
|
|
@@ -171,7 +178,7 @@ async function isRunningFromHydrogenMonorepo() {
|
|
|
171
178
|
}
|
|
172
179
|
function createNextRelease(latestRelease) {
|
|
173
180
|
const dependencies = { ...latestRelease.dependencies };
|
|
174
|
-
const devDependencies = { ...latestRelease.devDependencies };
|
|
181
|
+
const devDependencies = { ...latestRelease.devDependencies ?? {} };
|
|
175
182
|
if (dependencies["@shopify/hydrogen"]) {
|
|
176
183
|
dependencies["@shopify/hydrogen"] = "next";
|
|
177
184
|
}
|
|
@@ -272,7 +279,7 @@ function hasOutdatedDependencies({
|
|
|
272
279
|
}) {
|
|
273
280
|
return Object.entries({
|
|
274
281
|
...release.dependencies,
|
|
275
|
-
...release.devDependencies
|
|
282
|
+
...release.devDependencies ?? {}
|
|
276
283
|
}).some(([name, version]) => {
|
|
277
284
|
if (name === "@shopify/cli") return false;
|
|
278
285
|
const currentDependencyVersion = currentDependencies?.[name];
|
|
@@ -336,20 +343,31 @@ async function getSelectedRelease({
|
|
|
336
343
|
) : void 0;
|
|
337
344
|
return targetRelease ?? promptUpgradeOptions(currentVersion, availableUpgrades);
|
|
338
345
|
}
|
|
339
|
-
function
|
|
346
|
+
function getCumulativeRelease({
|
|
340
347
|
availableUpgrades,
|
|
341
348
|
selectedRelease,
|
|
342
349
|
currentVersion,
|
|
343
350
|
currentDependencies
|
|
344
351
|
}) {
|
|
345
352
|
const currentPinnedVersion = getAbsoluteVersion(currentVersion);
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
353
|
+
const empty = {
|
|
354
|
+
features: [],
|
|
355
|
+
fixes: [],
|
|
356
|
+
removeDependencies: [],
|
|
357
|
+
removeDevDependencies: [],
|
|
358
|
+
dependencies: {},
|
|
359
|
+
devDependencies: {}
|
|
360
|
+
};
|
|
361
|
+
if (!availableUpgrades?.length) return empty;
|
|
349
362
|
if (selectedRelease.dependencies?.["@shopify/hydrogen"] === "next") {
|
|
350
363
|
return {
|
|
364
|
+
...empty,
|
|
351
365
|
features: selectedRelease.features || [],
|
|
352
|
-
fixes: selectedRelease.fixes || []
|
|
366
|
+
fixes: selectedRelease.fixes || [],
|
|
367
|
+
removeDependencies: selectedRelease.removeDependencies ?? [],
|
|
368
|
+
removeDevDependencies: selectedRelease.removeDevDependencies ?? [],
|
|
369
|
+
dependencies: selectedRelease.dependencies ?? {},
|
|
370
|
+
devDependencies: selectedRelease.devDependencies ?? {}
|
|
353
371
|
};
|
|
354
372
|
}
|
|
355
373
|
const upgradingReleases = availableUpgrades.filter((release) => {
|
|
@@ -359,14 +377,65 @@ function getCummulativeRelease({
|
|
|
359
377
|
if (!isSameHydrogenVersion || !currentDependencies) return false;
|
|
360
378
|
return hasOutdatedDependencies({ release, currentDependencies });
|
|
361
379
|
});
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return acc;
|
|
367
|
-
},
|
|
368
|
-
{ features: [], fixes: [] }
|
|
380
|
+
const features = upgradingReleases.flatMap((r) => r.features);
|
|
381
|
+
const fixes = upgradingReleases.flatMap((r) => r.fixes);
|
|
382
|
+
const releasesByVersion = [...upgradingReleases].sort(
|
|
383
|
+
(a, b) => semver.compare(a.version, b.version)
|
|
369
384
|
);
|
|
385
|
+
const removedDepsAt = /* @__PURE__ */ new Map();
|
|
386
|
+
const removedDevDepsAt = /* @__PURE__ */ new Map();
|
|
387
|
+
releasesByVersion.forEach((release, i) => {
|
|
388
|
+
release.removeDependencies?.forEach((dep) => {
|
|
389
|
+
removedDepsAt.set(dep, i);
|
|
390
|
+
});
|
|
391
|
+
release.removeDevDependencies?.forEach((dep) => {
|
|
392
|
+
removedDevDepsAt.set(dep, i);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
const reinstalledDeps = /* @__PURE__ */ new Set();
|
|
396
|
+
const reinstalledDevDeps = /* @__PURE__ */ new Set();
|
|
397
|
+
for (let i = 0; i < releasesByVersion.length; i++) {
|
|
398
|
+
const release = releasesByVersion[i];
|
|
399
|
+
if (!release) continue;
|
|
400
|
+
const dependencies2 = release.dependencies ?? {};
|
|
401
|
+
const devDependencies2 = release.devDependencies ?? {};
|
|
402
|
+
Object.keys(dependencies2).forEach((dep) => {
|
|
403
|
+
const removalI = removedDepsAt.get(dep);
|
|
404
|
+
if (removalI !== void 0 && i >= removalI) {
|
|
405
|
+
reinstalledDeps.add(dep);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
Object.keys(devDependencies2).forEach((dep) => {
|
|
409
|
+
const removalI = removedDevDepsAt.get(dep);
|
|
410
|
+
if (removalI !== void 0 && i >= removalI) {
|
|
411
|
+
reinstalledDevDeps.add(dep);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
const removeDependencies = [
|
|
416
|
+
...new Set(
|
|
417
|
+
releasesByVersion.flatMap((r) => r.removeDependencies ?? []).filter((dep) => !reinstalledDeps.has(dep))
|
|
418
|
+
)
|
|
419
|
+
];
|
|
420
|
+
const removeDevDependencies = [
|
|
421
|
+
...new Set(
|
|
422
|
+
releasesByVersion.flatMap((r) => r.removeDevDependencies ?? []).filter((dep) => !reinstalledDevDeps.has(dep))
|
|
423
|
+
)
|
|
424
|
+
];
|
|
425
|
+
const dependencies = {};
|
|
426
|
+
const devDependencies = {};
|
|
427
|
+
for (const release of releasesByVersion) {
|
|
428
|
+
Object.assign(dependencies, release.dependencies ?? {});
|
|
429
|
+
Object.assign(devDependencies, release.devDependencies ?? {});
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
features,
|
|
433
|
+
fixes,
|
|
434
|
+
removeDependencies,
|
|
435
|
+
removeDevDependencies,
|
|
436
|
+
dependencies,
|
|
437
|
+
devDependencies
|
|
438
|
+
};
|
|
370
439
|
}
|
|
371
440
|
function displayConfirmation({
|
|
372
441
|
cumulativeRelease,
|
|
@@ -374,10 +443,11 @@ function displayConfirmation({
|
|
|
374
443
|
targetVersion
|
|
375
444
|
}) {
|
|
376
445
|
const { features, fixes } = cumulativeRelease;
|
|
377
|
-
|
|
446
|
+
const allRemovedPackages = getAllRemovedPackages(cumulativeRelease);
|
|
447
|
+
if (features.length || fixes.length || allRemovedPackages.length) {
|
|
378
448
|
renderInfo({
|
|
379
449
|
headline: `Included in this upgrade:`,
|
|
380
|
-
|
|
450
|
+
// @ts-expect-error - filter(Boolean) removes falsy values, leaving only objects
|
|
381
451
|
customSections: [
|
|
382
452
|
features.length && {
|
|
383
453
|
title: "Features",
|
|
@@ -398,6 +468,16 @@ function displayConfirmation({
|
|
|
398
468
|
}
|
|
399
469
|
}
|
|
400
470
|
]
|
|
471
|
+
},
|
|
472
|
+
allRemovedPackages.length && {
|
|
473
|
+
title: "Removed packages",
|
|
474
|
+
body: [
|
|
475
|
+
{
|
|
476
|
+
list: {
|
|
477
|
+
items: allRemovedPackages
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
]
|
|
401
481
|
}
|
|
402
482
|
].filter(Boolean)
|
|
403
483
|
});
|
|
@@ -461,10 +541,20 @@ function maybeIncludeDependency({
|
|
|
461
541
|
function buildUpgradeCommandArgs({
|
|
462
542
|
selectedRelease,
|
|
463
543
|
currentDependencies,
|
|
464
|
-
targetVersion
|
|
544
|
+
targetVersion,
|
|
545
|
+
cumulativeDependencies,
|
|
546
|
+
cumulativeDevDependencies
|
|
465
547
|
}) {
|
|
466
548
|
const args = [];
|
|
467
|
-
|
|
549
|
+
const effectiveDependencies = {
|
|
550
|
+
...cumulativeDependencies ?? {},
|
|
551
|
+
...selectedRelease.dependencies
|
|
552
|
+
};
|
|
553
|
+
const effectiveDevDependencies = {
|
|
554
|
+
...cumulativeDevDependencies ?? {},
|
|
555
|
+
...selectedRelease.devDependencies ?? {}
|
|
556
|
+
};
|
|
557
|
+
for (const dependency of Object.entries(effectiveDependencies)) {
|
|
468
558
|
const shouldUpgradeDep = maybeIncludeDependency({
|
|
469
559
|
currentDependencies,
|
|
470
560
|
dependency,
|
|
@@ -480,7 +570,7 @@ function buildUpgradeCommandArgs({
|
|
|
480
570
|
)}`
|
|
481
571
|
);
|
|
482
572
|
}
|
|
483
|
-
for (const dependency of Object.entries(
|
|
573
|
+
for (const dependency of Object.entries(effectiveDevDependencies)) {
|
|
484
574
|
const shouldUpgradeDep = maybeIncludeDependency({
|
|
485
575
|
currentDependencies,
|
|
486
576
|
dependency,
|
|
@@ -497,7 +587,7 @@ function buildUpgradeCommandArgs({
|
|
|
497
587
|
);
|
|
498
588
|
}
|
|
499
589
|
const currentRemix = Object.entries(currentDependencies).find(isRemixDependency);
|
|
500
|
-
const selectedRemix = Object.entries(
|
|
590
|
+
const selectedRemix = Object.entries(effectiveDependencies).find(
|
|
501
591
|
isRemixDependency
|
|
502
592
|
);
|
|
503
593
|
if (currentRemix && selectedRemix) {
|
|
@@ -514,7 +604,7 @@ function buildUpgradeCommandArgs({
|
|
|
514
604
|
const currentReactRouter = Object.entries(currentDependencies).find(
|
|
515
605
|
isReactRouterDependency
|
|
516
606
|
);
|
|
517
|
-
const selectedReactRouter = Object.entries(
|
|
607
|
+
const selectedReactRouter = Object.entries(effectiveDependencies).find(
|
|
518
608
|
isReactRouterDependency
|
|
519
609
|
);
|
|
520
610
|
if (selectedReactRouter) {
|
|
@@ -537,12 +627,16 @@ async function upgradeNodeModules({
|
|
|
537
627
|
appPath,
|
|
538
628
|
selectedRelease,
|
|
539
629
|
currentDependencies,
|
|
540
|
-
targetVersion
|
|
630
|
+
targetVersion,
|
|
631
|
+
cumulativeRemoveDependencies,
|
|
632
|
+
cumulativeRemoveDevDependencies,
|
|
633
|
+
cumulativeDependencies,
|
|
634
|
+
cumulativeDevDependencies
|
|
541
635
|
}) {
|
|
542
636
|
const tasks = [];
|
|
543
637
|
const depsToRemove = [
|
|
544
|
-
...
|
|
545
|
-
...
|
|
638
|
+
...cumulativeRemoveDependencies,
|
|
639
|
+
...cumulativeRemoveDevDependencies
|
|
546
640
|
].filter((dep) => dep in currentDependencies);
|
|
547
641
|
if (depsToRemove.length > 0) {
|
|
548
642
|
tasks.push({
|
|
@@ -559,17 +653,24 @@ async function upgradeNodeModules({
|
|
|
559
653
|
const upgradeArgs = buildUpgradeCommandArgs({
|
|
560
654
|
selectedRelease,
|
|
561
655
|
currentDependencies,
|
|
562
|
-
targetVersion
|
|
656
|
+
targetVersion,
|
|
657
|
+
cumulativeDependencies,
|
|
658
|
+
cumulativeDevDependencies
|
|
563
659
|
});
|
|
564
660
|
if (upgradeArgs.length > 0) {
|
|
565
661
|
tasks.push({
|
|
566
662
|
title: `Upgrading dependencies`,
|
|
567
663
|
task: async () => {
|
|
568
|
-
await
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
664
|
+
const packageManager = await getPackageManager(appPath);
|
|
665
|
+
const command = packageManager === "npm" ? "install" : packageManager === "yarn" ? "add" : packageManager === "pnpm" ? "add" : packageManager === "bun" ? "install" : "install";
|
|
666
|
+
const extraArgs = packageManager === "npm" || packageManager === "unknown" ? ["--legacy-peer-deps"] : [];
|
|
667
|
+
await exec(
|
|
668
|
+
resolvePackageManagerName(packageManager),
|
|
669
|
+
[command, ...extraArgs, ...upgradeArgs],
|
|
670
|
+
{
|
|
671
|
+
cwd: appPath
|
|
672
|
+
}
|
|
673
|
+
);
|
|
573
674
|
}
|
|
574
675
|
});
|
|
575
676
|
}
|
|
@@ -577,6 +678,9 @@ async function upgradeNodeModules({
|
|
|
577
678
|
await renderTasks(tasks, {});
|
|
578
679
|
}
|
|
579
680
|
}
|
|
681
|
+
function resolvePackageManagerName(packageManager) {
|
|
682
|
+
return packageManager === "unknown" ? "npm" : packageManager;
|
|
683
|
+
}
|
|
580
684
|
async function uninstallNodeModules({
|
|
581
685
|
directory,
|
|
582
686
|
packageManager,
|
|
@@ -584,8 +688,12 @@ async function uninstallNodeModules({
|
|
|
584
688
|
}) {
|
|
585
689
|
if (args.length === 0) return;
|
|
586
690
|
const command = packageManager === "npm" ? "uninstall" : packageManager === "yarn" ? "remove" : packageManager === "pnpm" ? "remove" : packageManager === "bun" ? "remove" : "uninstall";
|
|
587
|
-
const
|
|
588
|
-
await exec(
|
|
691
|
+
const extraArgs = packageManager === "npm" || packageManager === "unknown" ? ["--legacy-peer-deps"] : [];
|
|
692
|
+
await exec(
|
|
693
|
+
resolvePackageManagerName(packageManager),
|
|
694
|
+
[command, ...extraArgs, ...args],
|
|
695
|
+
{ cwd: directory }
|
|
696
|
+
);
|
|
589
697
|
}
|
|
590
698
|
function appendRemixDependencies({
|
|
591
699
|
currentDependencies,
|
|
@@ -787,7 +895,8 @@ async function generateUpgradeInstructionsFile({
|
|
|
787
895
|
{ featuresMd: [], breakingChangesMd: [] }
|
|
788
896
|
);
|
|
789
897
|
const fixesMd = cumulativeRelease.fixes.filter((fixes) => fixes.steps).map(generateStepMd);
|
|
790
|
-
|
|
898
|
+
const allRemovedPackages = getAllRemovedPackages(cumulativeRelease);
|
|
899
|
+
if (!featuresMd.length && !fixesMd.length && !breakingChangesMd.length && !allRemovedPackages.length) {
|
|
791
900
|
renderInfo({
|
|
792
901
|
headline: `No upgrade instructions generated`,
|
|
793
902
|
body: `There are no additional upgrade instructions for this version.`
|
|
@@ -827,6 +936,16 @@ ${fixesMd.join(
|
|
|
827
936
|
"\n"
|
|
828
937
|
)}`;
|
|
829
938
|
}
|
|
939
|
+
if (allRemovedPackages.length) {
|
|
940
|
+
md += fixesMd.length ? "\n\n----\n\n" : "\n";
|
|
941
|
+
md += `## Removed packages
|
|
942
|
+
|
|
943
|
+
The following packages have been removed as part of this upgrade:
|
|
944
|
+
|
|
945
|
+
`;
|
|
946
|
+
md += allRemovedPackages.map((dep) => `- \`${dep}\``).join("\n");
|
|
947
|
+
md += "\n";
|
|
948
|
+
}
|
|
830
949
|
const filePath = joinPath(instructionsFolderPath, filename);
|
|
831
950
|
try {
|
|
832
951
|
await isDirectory(instructionsFolderPath);
|
|
@@ -859,6 +978,13 @@ async function displayDevUpgradeNotice({
|
|
|
859
978
|
const { currentVersion, currentDependencies } = await getHydrogenVersion({
|
|
860
979
|
appPath
|
|
861
980
|
});
|
|
981
|
+
if (currentVersion.startsWith("workspace:")) {
|
|
982
|
+
renderInfo({
|
|
983
|
+
headline: "Using monorepo @shopify/hydrogen dependency",
|
|
984
|
+
body: "This project uses the workspace protocol for @shopify/hydrogen, so upgrade notices are skipped during local monorepo development."
|
|
985
|
+
});
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
862
988
|
const isPrerelease = semver.prerelease(currentVersion);
|
|
863
989
|
if (isPrerelease || /^[a-z]+$/i.test(currentVersion)) {
|
|
864
990
|
return;
|
|
@@ -882,7 +1008,15 @@ async function displayDevUpgradeNotice({
|
|
|
882
1008
|
) : changelog.releases.findIndex(
|
|
883
1009
|
(release) => getAbsoluteVersion(release.version) === pinnedCurrentVersion
|
|
884
1010
|
);
|
|
885
|
-
|
|
1011
|
+
let relevantReleases;
|
|
1012
|
+
if (currentReleaseIndex === -1) {
|
|
1013
|
+
const insertionIndex = changelog.releases.findIndex(
|
|
1014
|
+
(release) => semver.lte(getAbsoluteVersion(release.version), pinnedCurrentVersion)
|
|
1015
|
+
);
|
|
1016
|
+
relevantReleases = insertionIndex === -1 ? changelog.releases : changelog.releases.slice(0, insertionIndex);
|
|
1017
|
+
} else {
|
|
1018
|
+
relevantReleases = changelog.releases.slice(0, currentReleaseIndex);
|
|
1019
|
+
}
|
|
886
1020
|
const nextReleases = Object.values(
|
|
887
1021
|
[...relevantReleases].reverse().reduce(
|
|
888
1022
|
(acc, release) => {
|
|
@@ -891,7 +1025,7 @@ async function displayDevUpgradeNotice({
|
|
|
891
1025
|
},
|
|
892
1026
|
{}
|
|
893
1027
|
)
|
|
894
|
-
).slice(0, 5);
|
|
1028
|
+
).reverse().slice(0, 5);
|
|
895
1029
|
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.`;
|
|
896
1030
|
const cliCommand = await getCliCommand();
|
|
897
1031
|
renderInfo({
|
|
@@ -939,4 +1073,4 @@ async function displayDevUpgradeNotice({
|
|
|
939
1073
|
}
|
|
940
1074
|
}
|
|
941
1075
|
|
|
942
|
-
export { buildUpgradeCommandArgs, Upgrade as default, displayConfirmation, displayDevUpgradeNotice, getAbsoluteVersion, getAvailableUpgrades, getChangelog,
|
|
1076
|
+
export { buildUpgradeCommandArgs, Upgrade as default, displayConfirmation, displayDevUpgradeNotice, generateUpgradeInstructionsFile, getAbsoluteVersion, getAvailableUpgrades, getChangelog, getCumulativeRelease, getHydrogenVersion, getPackageVersion, getSelectedRelease, isRunningFromHydrogenMonorepo, runUpgrade, upgradeNodeModules, validateUpgrade };
|
package/dist/lib/build.js
CHANGED
|
@@ -69,12 +69,11 @@ function getSkeletonNodeModules() {
|
|
|
69
69
|
return joinPath(getSkeletonSourceDir(), "node_modules");
|
|
70
70
|
}
|
|
71
71
|
async function getRepoNodeModules() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (!nodeModulesPath && isHydrogenMonorepo) {
|
|
75
|
-
nodeModulesPath = joinPath(dirname(monorepoPackagesPath), "node_modules");
|
|
72
|
+
if (isHydrogenMonorepo) {
|
|
73
|
+
return getSkeletonNodeModules();
|
|
76
74
|
}
|
|
77
|
-
|
|
75
|
+
const { stdout } = await execAsync("npm root");
|
|
76
|
+
return stdout.trim();
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
export { ASSETS_DIR_PREFIX, ASSETS_STARTER_DIR, ASSETS_STARTER_DIR_ROUTES, getAssetsDir, getPkgJsonPath, getRepoNodeModules, getSkeletonNodeModules, getSkeletonSourceDir, getStarterDir, getTemplateAppFile, hydrogenPackagesPath, isHydrogenMonorepo };
|
|
@@ -44,7 +44,7 @@ function hydrogenBundleAnalyzer(pluginOptions) {
|
|
|
44
44
|
modsToAnalyze.map(async (mod) => {
|
|
45
45
|
const relativeModId = relativePath(root, mod.id);
|
|
46
46
|
const modBundleInfo = workerFile.modules[mod.id];
|
|
47
|
-
const originalCodeBytes = modBundleInfo?.originalLength
|
|
47
|
+
const originalCodeBytes = typeof modBundleInfo?.originalLength === "number" ? modBundleInfo.originalLength : mod.code?.length ?? 0;
|
|
48
48
|
let resultingCodeBytes = modBundleInfo?.renderedLength ?? 0;
|
|
49
49
|
if (pluginOptions?.minify && modBundleInfo?.code) {
|
|
50
50
|
const minifiedCode = await pluginOptions.minify(modBundleInfo.code, mod.id).catch(() => null);
|
|
@@ -115,33 +115,19 @@ function hydrogenBundleAnalyzer(pluginOptions) {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
|
-
|
|
118
|
+
this.emitFile({
|
|
119
119
|
type: "asset",
|
|
120
120
|
fileName: BUNDLE_ANALYZER_JSON_FILE,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
originalFileNames: [BUNDLE_ANALYZER_JSON_FILE],
|
|
125
|
-
// name and originalFileName should be deprecated .. but
|
|
126
|
-
// for some reason, removing them breaks typescript check
|
|
127
|
-
name: BUNDLE_ANALYZER_JSON_FILE,
|
|
128
|
-
originalFileName: BUNDLE_ANALYZER_JSON_FILE
|
|
129
|
-
};
|
|
130
|
-
bundle[BUNDLE_ANALYZER_HTML_FILE] = {
|
|
121
|
+
source: JSON.stringify(metafile, null, 2)
|
|
122
|
+
});
|
|
123
|
+
this.emitFile({
|
|
131
124
|
type: "asset",
|
|
132
125
|
fileName: BUNDLE_ANALYZER_HTML_FILE,
|
|
133
|
-
needsCodeReference: false,
|
|
134
126
|
source: injectAnalyzerTemplateData(
|
|
135
127
|
analysisTemplate,
|
|
136
128
|
JSON.stringify(metafile)
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
originalFileNames: [BUNDLE_ANALYZER_HTML_FILE],
|
|
140
|
-
// name and originalFileName should be deprecated .. but
|
|
141
|
-
// for some reason, removing them breaks typescript check
|
|
142
|
-
name: BUNDLE_ANALYZER_HTML_FILE,
|
|
143
|
-
originalFileName: BUNDLE_ANALYZER_HTML_FILE
|
|
144
|
-
};
|
|
129
|
+
)
|
|
130
|
+
});
|
|
145
131
|
}
|
|
146
132
|
};
|
|
147
133
|
}
|
|
@@ -24,10 +24,12 @@ function missingLockfileWarning(shouldExit) {
|
|
|
24
24
|
renderWarning({ headline, body, nextSteps });
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function multipleLockfilesWarning(
|
|
28
|
-
const lockfileList =
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
function multipleLockfilesWarning(foundPackageManagers, shouldExit) {
|
|
28
|
+
const lockfileList = foundPackageManagers.map(
|
|
29
|
+
({ packageManager, foundLockfile }) => {
|
|
30
|
+
return `${foundLockfile} (created by ${packageManager.name})`;
|
|
31
|
+
}
|
|
32
|
+
);
|
|
31
33
|
const headline = "Multiple lockfiles found";
|
|
32
34
|
const body = [
|
|
33
35
|
`Your project contains more than one lockfile. This can cause version conflicts when installing and deploying your app. The following lockfiles were detected:
|
|
@@ -57,8 +59,15 @@ async function checkLockfileStatus(directory, shouldExit = false) {
|
|
|
57
59
|
if (isHydrogenMonorepo && !process.env.SHOPIFY_UNIT_TEST) return;
|
|
58
60
|
const foundPackageManagers = [];
|
|
59
61
|
for (const packageManager of packageManagers) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
const allLockfiles = [
|
|
63
|
+
packageManager.lockfile,
|
|
64
|
+
...packageManager.alternativeLockfiles || []
|
|
65
|
+
];
|
|
66
|
+
for (const lockfile2 of allLockfiles) {
|
|
67
|
+
if (await fileExists(resolvePath(directory, lockfile2))) {
|
|
68
|
+
foundPackageManagers.push({ packageManager, foundLockfile: lockfile2 });
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
if (foundPackageManagers.length === 0) {
|
|
@@ -67,7 +76,7 @@ async function checkLockfileStatus(directory, shouldExit = false) {
|
|
|
67
76
|
if (foundPackageManagers.length > 1) {
|
|
68
77
|
return multipleLockfilesWarning(foundPackageManagers, shouldExit);
|
|
69
78
|
}
|
|
70
|
-
const lockfile = foundPackageManagers[0].
|
|
79
|
+
const lockfile = foundPackageManagers[0].foundLockfile;
|
|
71
80
|
const ignoredLockfile = await checkIfIgnoredInGitRepository(directory, [
|
|
72
81
|
lockfile
|
|
73
82
|
]).catch(() => {
|
package/dist/lib/codegen.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { getCodeFormatOptions, formatCode } from './format-code.js';
|
|
4
4
|
import { renderInfo, renderWarning } from '@shopify/cli-kit/node/ui';
|
|
5
|
-
import { relativePath,
|
|
5
|
+
import { relativePath, joinPath, resolvePath, basename } from '@shopify/cli-kit/node/path';
|
|
6
6
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
7
7
|
import { importLocal } from './import-utils.js';
|
|
8
8
|
|
|
@@ -283,7 +283,7 @@ function findGqlProject(schemaFilepath, gqlConfig) {
|
|
|
283
283
|
);
|
|
284
284
|
}
|
|
285
285
|
async function addHooksToHydrogenOptions(codegenConfig, { rootDirectory }) {
|
|
286
|
-
const name = Symbol.for("name");
|
|
286
|
+
const name = /* @__PURE__ */ Symbol.for("name");
|
|
287
287
|
const hydrogenProjectsOptions = Object.values(codegenConfig.generates).filter(
|
|
288
288
|
(value) => {
|
|
289
289
|
const foundPreset = (Array.isArray(value) ? value[0] : value)?.preset;
|
package/dist/lib/format-code.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { extname } from '@shopify/cli-kit/node/path';
|
|
2
|
-
import
|
|
2
|
+
import { resolveConfig, format } from 'prettier';
|
|
3
3
|
import * as FS from 'fs/promises';
|
|
4
4
|
import * as Path from 'path';
|
|
5
5
|
|
|
@@ -12,14 +12,14 @@ const DEFAULT_PRETTIER_CONFIG = {
|
|
|
12
12
|
async function getCodeFormatOptions(filePath = process.cwd()) {
|
|
13
13
|
const pathToUse = (await FS.lstat(filePath)).isFile() ? filePath : Path.resolve(filePath, "prettier.file");
|
|
14
14
|
try {
|
|
15
|
-
return await
|
|
15
|
+
return await resolveConfig(pathToUse) || DEFAULT_PRETTIER_CONFIG;
|
|
16
16
|
} catch {
|
|
17
17
|
return DEFAULT_PRETTIER_CONFIG;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
async function formatCode(content, config = DEFAULT_PRETTIER_CONFIG, filePath = "") {
|
|
21
21
|
const ext = extname(filePath);
|
|
22
|
-
return
|
|
22
|
+
return format(content, {
|
|
23
23
|
// Specify the TypeScript parser for ts/tsx files. Otherwise
|
|
24
24
|
// we need to use the babel parser instead of the default parser,
|
|
25
25
|
// because prettier will print a warning.
|
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
2
2
|
import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
|
|
3
3
|
|
|
4
|
+
const KNOWN_USER_ERRORS = [
|
|
5
|
+
{
|
|
6
|
+
pattern: "app is not installed",
|
|
7
|
+
abort: [
|
|
8
|
+
"Hydrogen sales channel isn't installed",
|
|
9
|
+
"Install the Hydrogen sales channel on your store to start creating and linking Hydrogen storefronts: https://apps.shopify.com/hydrogen"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
pattern: "Access denied for hydrogenStorefrontCreate field",
|
|
14
|
+
abort: [
|
|
15
|
+
"Couldn't connect storefront to Shopify",
|
|
16
|
+
[
|
|
17
|
+
"Common reasons for this error include:",
|
|
18
|
+
{
|
|
19
|
+
list: {
|
|
20
|
+
items: [
|
|
21
|
+
"The Hydrogen sales channel isn't installed on the store.",
|
|
22
|
+
"You don't have the required account permission to manage apps or channels.",
|
|
23
|
+
"You're trying to connect to an ineligible store type (Trial, Development store)"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
pattern: "Access denied for hydrogenStorefronts field",
|
|
32
|
+
abort: [
|
|
33
|
+
"Couldn't access Hydrogen storefronts",
|
|
34
|
+
[
|
|
35
|
+
"Common reasons for this error include:",
|
|
36
|
+
{
|
|
37
|
+
list: {
|
|
38
|
+
items: [
|
|
39
|
+
"You don't have full access to apps or access to the Hydrogen channel.",
|
|
40
|
+
"The Hydrogen sales channel isn't installed on the store."
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
];
|
|
4
48
|
async function adminRequest(query, session, variables) {
|
|
5
49
|
const api = "Admin";
|
|
6
50
|
const url = `https://${session.storeFqdn}/admin/api/unstable/graphql.json`;
|
|
@@ -14,29 +58,10 @@ async function adminRequest(query, session, variables) {
|
|
|
14
58
|
});
|
|
15
59
|
} catch (error) {
|
|
16
60
|
const errors = error.errors;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
if (errors?.some?.(
|
|
24
|
-
(error2) => error2.message.includes(
|
|
25
|
-
"Access denied for hydrogenStorefrontCreate field"
|
|
26
|
-
)
|
|
27
|
-
)) {
|
|
28
|
-
throw new AbortError("Couldn't connect storefront to Shopify", [
|
|
29
|
-
"Common reasons for this error include:",
|
|
30
|
-
{
|
|
31
|
-
list: {
|
|
32
|
-
items: [
|
|
33
|
-
"The Hydrogen sales channel isn't installed on the store.",
|
|
34
|
-
"You don't have the required account permission to manage apps or channels.",
|
|
35
|
-
"You're trying to connect to an ineligible store type (Trial, Development store)"
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
]);
|
|
61
|
+
for (const { pattern, abort } of KNOWN_USER_ERRORS) {
|
|
62
|
+
if (errors?.some?.((e) => e.message.includes(pattern))) {
|
|
63
|
+
throw new AbortError(...abort);
|
|
64
|
+
}
|
|
40
65
|
}
|
|
41
66
|
throw error;
|
|
42
67
|
}
|
package/dist/lib/import-utils.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
3
4
|
import { findUpAndReadPackageJson } from '@shopify/cli-kit/node/node-package-manager';
|
|
4
5
|
import { joinPath, dirname } from '@shopify/cli-kit/node/path';
|
|
5
6
|
|
|
6
7
|
const require2 = createRequire(import.meta.url);
|
|
7
8
|
async function importVite(root) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
let vitePath;
|
|
10
|
+
try {
|
|
11
|
+
vitePath = require2.resolve(
|
|
12
|
+
"vite",
|
|
13
|
+
process.env.SHOPIFY_UNIT_TEST ? void 0 : { paths: [root] }
|
|
14
|
+
);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error instanceof Error && error.code === "MODULE_NOT_FOUND") {
|
|
17
|
+
throw new AbortError(
|
|
18
|
+
"Could not find the 'vite' package in your project.",
|
|
19
|
+
"Hydrogen uses Vite to run this command.",
|
|
20
|
+
[
|
|
21
|
+
"Run this command from the root directory of your Hydrogen app.",
|
|
22
|
+
"Install your project dependencies (for example, by running `npm install`) and try again."
|
|
23
|
+
]
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
12
28
|
const vitePackageJson = await findUpAndReadPackageJson(vitePath);
|
|
13
29
|
let viteNodeIndexFile = vitePackageJson.content.exports?.["."];
|
|
14
30
|
if (typeof viteNodeIndexFile !== "string") {
|