@shopify/cli-hydrogen 11.1.9 → 11.1.11

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.
Files changed (46) hide show
  1. package/dist/assets/hydrogen/starter/CHANGELOG.md +28 -0
  2. package/dist/assets/hydrogen/starter/app/components/Aside.tsx +4 -2
  3. package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +6 -3
  4. package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +117 -23
  5. package/dist/assets/hydrogen/starter/app/components/Header.tsx +3 -3
  6. package/dist/assets/hydrogen/starter/app/components/MockShopNotice.tsx +20 -0
  7. package/dist/assets/hydrogen/starter/app/entry.client.tsx +2 -3
  8. package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +14 -53
  9. package/dist/assets/hydrogen/starter/app/routes/_index.tsx +15 -9
  10. package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +1 -1
  11. package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +13 -13
  12. package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +1 -1
  13. package/dist/assets/hydrogen/starter/app/routes/account.tsx +4 -7
  14. package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +2 -9
  15. package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +1 -4
  16. package/dist/assets/hydrogen/starter/app/routes/cart.tsx +1 -5
  17. package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +1 -3
  18. package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +2 -8
  19. package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +1 -4
  20. package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +1 -1
  21. package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +2 -9
  22. package/dist/assets/hydrogen/starter/app/routes/search.tsx +18 -12
  23. package/dist/assets/hydrogen/starter/app/styles/app.css +51 -0
  24. package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +3 -3
  25. package/dist/assets/hydrogen/starter/guides/search/search.md +1 -1
  26. package/dist/assets/hydrogen/starter/package.json +10 -10
  27. package/dist/assets/hydrogen/starter/vite.config.ts +1 -1
  28. package/dist/assets/hydrogen/vite/vite.config.js +1 -1
  29. package/dist/commands/hydrogen/dev.js +0 -4
  30. package/dist/commands/hydrogen/init.d.ts +2 -4
  31. package/dist/commands/hydrogen/init.js +2 -8
  32. package/dist/commands/hydrogen/preview.js +1 -1
  33. package/dist/commands/hydrogen/setup/css.js +1 -1
  34. package/dist/commands/hydrogen/setup/vite.js +1 -1
  35. package/dist/commands/hydrogen/setup.js +31 -33
  36. package/dist/commands/hydrogen/upgrade.js +7 -0
  37. package/dist/lib/build.js +4 -5
  38. package/dist/lib/codegen.js +2 -2
  39. package/dist/lib/format-code.js +3 -3
  40. package/dist/lib/mini-oxygen/workerd.js +3 -5
  41. package/dist/lib/onboarding/common.js +21 -26
  42. package/dist/lib/onboarding/local.js +46 -59
  43. package/dist/lib/template-pack.js +84 -0
  44. package/oclif.manifest.json +2 -9
  45. package/package.json +18 -15
  46. package/dist/lib/react-router-version-check.js +0 -82
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/blogs.$blogHandle._index';
6
3
  import {Image, getPaginationVariables} from '@shopify/hydrogen';
7
4
  import type {ArticleItemFragment} from 'storefrontapi.generated';
@@ -26,11 +23,7 @@ export async function loader(args: Route.LoaderArgs) {
26
23
  * Load data necessary for rendering content above the fold. This is the critical data
27
24
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
28
25
  */
29
- async function loadCriticalData({
30
- context,
31
- request,
32
- params,
33
- }: Route.LoaderArgs) {
26
+ async function loadCriticalData({context, request, params}: Route.LoaderArgs) {
34
27
  const paginationVariables = getPaginationVariables(request, {
35
28
  pageBy: 4,
36
29
  });
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/blogs._index';
6
3
  import {getPaginationVariables} from '@shopify/hydrogen';
7
4
  import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
@@ -1,8 +1,4 @@
1
- import {
2
- useLoaderData,
3
- data,
4
- type HeadersFunction,
5
- } from 'react-router';
1
+ import {useLoaderData, data, type HeadersFunction} from 'react-router';
6
2
  import type {Route} from './+types/cart';
7
3
  import type {CartQueryDataReturn} from '@shopify/hydrogen';
8
4
  import {CartForm} from '@shopify/hydrogen';
@@ -1,7 +1,5 @@
1
1
  import type {Route} from './+types/collections.all';
2
- import {
3
- useLoaderData,
4
- } from 'react-router';
2
+ import {useLoaderData} from 'react-router';
5
3
  import {getPaginationVariables, Image, Money} from '@shopify/hydrogen';
6
4
  import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
7
5
  import {ProductItem} from '~/components/ProductItem';
@@ -1,6 +1,4 @@
1
- import {
2
- useLoaderData,
3
- } from 'react-router';
1
+ import {useLoaderData} from 'react-router';
4
2
  import type {Route} from './+types/pages.$handle';
5
3
  import {redirectIfHandleIsLocalized} from '~/lib/redirect';
6
4
 
@@ -22,11 +20,7 @@ export async function loader(args: Route.LoaderArgs) {
22
20
  * Load data necessary for rendering content above the fold. This is the critical data
23
21
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
24
22
  */
25
- async function loadCriticalData({
26
- context,
27
- request,
28
- params,
29
- }: Route.LoaderArgs) {
23
+ async function loadCriticalData({context, request, params}: Route.LoaderArgs) {
30
24
  if (!params.handle) {
31
25
  throw new Error('Missing page handle');
32
26
  }
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/policies.$handle';
6
3
  import {type Shop} from '@shopify/hydrogen/storefront-api-types';
7
4
 
@@ -4,7 +4,7 @@ import type {PoliciesQuery, PolicyItemFragment} from 'storefrontapi.generated';
4
4
 
5
5
  export async function loader({context}: Route.LoaderArgs) {
6
6
  const data: PoliciesQuery = await context.storefront.query(POLICIES_QUERY);
7
-
7
+
8
8
  const shopPolicies = data.shop;
9
9
  const policies: PolicyItemFragment[] = [
10
10
  shopPolicies?.privacyPolicy,
@@ -1,7 +1,4 @@
1
- import {
2
- redirect,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {redirect, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/products.$handle';
6
3
  import {
7
4
  getSelectedProductOptions,
@@ -40,11 +37,7 @@ export async function loader(args: Route.LoaderArgs) {
40
37
  * Load data necessary for rendering content above the fold. This is the critical data
41
38
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
42
39
  */
43
- async function loadCriticalData({
44
- context,
45
- params,
46
- request,
47
- }: Route.LoaderArgs) {
40
+ async function loadCriticalData({context, params, request}: Route.LoaderArgs) {
48
41
  const {handle} = params;
49
42
  const {storefront} = context;
50
43
 
@@ -1,6 +1,4 @@
1
- import {
2
- useLoaderData,
3
- } from 'react-router';
1
+ import {useLoaderData} from 'react-router';
4
2
  import type {Route} from './+types/search';
5
3
  import {getPaginationVariables, Analytics} from '@shopify/hydrogen';
6
4
  import {SearchForm} from '~/components/SearchForm';
@@ -10,7 +8,10 @@ import {
10
8
  type PredictiveSearchReturn,
11
9
  getEmptyPredictiveSearchResult,
12
10
  } from '~/lib/search';
13
- import type {RegularSearchQuery, PredictiveSearchQuery} from 'storefrontapi.generated';
11
+ import type {
12
+ RegularSearchQuery,
13
+ PredictiveSearchQuery,
14
+ } from 'storefrontapi.generated';
14
15
 
15
16
  export const meta: Route.MetaFunction = () => {
16
17
  return [{title: `Hydrogen | Search`}];
@@ -225,9 +226,13 @@ async function regularSearch({
225
226
  const term = String(url.searchParams.get('q') || '');
226
227
 
227
228
  // Search articles, pages, and products for the `q` term
228
- const {errors, ...items}: {errors?: Array<{message: string}>} & RegularSearchQuery = await storefront.query(SEARCH_QUERY, {
229
- variables: {...variables, term},
230
- });
229
+ const {
230
+ errors,
231
+ ...items
232
+ }: {errors?: Array<{message: string}>} & RegularSearchQuery =
233
+ await storefront.query(SEARCH_QUERY, {
234
+ variables: {...variables, term},
235
+ });
231
236
 
232
237
  if (!items) {
233
238
  throw new Error('No search data returned from Shopify API');
@@ -389,17 +394,18 @@ async function predictiveSearch({
389
394
  if (!term) return {type, term, result: getEmptyPredictiveSearchResult()};
390
395
 
391
396
  // Predictively search articles, collections, pages, products, and queries (suggestions)
392
- const {predictiveSearch: items, errors}: PredictiveSearchQuery & {errors?: Array<{message: string}>} = await storefront.query(
393
- PREDICTIVE_SEARCH_QUERY,
394
- {
397
+ const {
398
+ predictiveSearch: items,
399
+ errors,
400
+ }: PredictiveSearchQuery & {errors?: Array<{message: string}>} =
401
+ await storefront.query(PREDICTIVE_SEARCH_QUERY, {
395
402
  variables: {
396
403
  // customize search options as needed
397
404
  limit,
398
405
  limitScope: 'EACH',
399
406
  term,
400
407
  },
401
- },
402
- );
408
+ });
403
409
 
404
410
  if (errors) {
405
411
  throw new Error(
@@ -22,6 +22,57 @@ img {
22
22
  cursor: pointer;
23
23
  }
24
24
 
25
+ /*
26
+ * --------------------------------------------------
27
+ * components/MockShopNotice
28
+ * --------------------------------------------------
29
+ */
30
+ .mock-shop-notice {
31
+ background: var(--color-light);
32
+ border: 1px solid var(--color-dark);
33
+ border-left-width: 0.5rem;
34
+ margin: 1rem 0;
35
+ padding: 0;
36
+
37
+ .inner {
38
+ padding: 0.875rem 1rem;
39
+ }
40
+
41
+ h2 {
42
+ font-size: 1.6rem;
43
+ font-weight: 700;
44
+ line-height: 1.4;
45
+ }
46
+
47
+ p {
48
+ font-size: 1rem;
49
+ line-height: 1.4;
50
+ margin-bottom: 0.5rem;
51
+ }
52
+
53
+ footer {
54
+ background: rgba(0, 0, 0, 0.06);
55
+ padding: 0.5rem 1rem;
56
+ }
57
+
58
+ .small {
59
+ font-size: 0.875rem;
60
+ line-height: 1.4;
61
+ margin-bottom: 0.5rem;
62
+ }
63
+
64
+ code {
65
+ background: rgba(0, 0, 0, 0.06);
66
+ border-radius: 0.25rem;
67
+ padding: 0.1em 0.3em;
68
+ }
69
+
70
+ a {
71
+ text-decoration: underline;
72
+ text-underline-offset: 6px;
73
+ }
74
+ }
75
+
25
76
  /*
26
77
  * --------------------------------------------------
27
78
  * components/Aside
@@ -15,7 +15,7 @@ This integration uses the storefront API (SFAPI) [predictiveSearch](https://shop
15
15
 
16
16
  | File | Description |
17
17
  | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
18
- | [`app/components/SearchFormPredictive.tsx`](../../app/components/SearchFormPredictive.tsx) | A fully customizable form component configured to make form `GET` requests to the `/search` route. |
18
+ | [`app/components/SearchFormPredictive.tsx`](../../app/components/SearchFormPredictive.tsx) | A fully customizable form component configured to make form `GET` requests to the `/search` route. |
19
19
  | [`app/components/SearchResultsPredictive.tsx`](../../app/components/SearchResultsPredictive.tsx) | A fully customizable search results wrapper, that provides compound components to render `articles`, `pages`, `products`, `collections` and `queries`. |
20
20
 
21
21
  ## Instructions
@@ -217,10 +217,10 @@ export async function loader({request, context}: LoaderFunctionArgs) {
217
217
  const isPredictive = url.searchParams.has('predictive');
218
218
 
219
219
  if (!isPredictive) {
220
- return {}
220
+ return {};
221
221
  }
222
222
 
223
- const searchPromise = predictiveSearch({request, context})
223
+ const searchPromise = predictiveSearch({request, context});
224
224
 
225
225
  searchPromise.catch((error: Error) => {
226
226
  console.error(error);
@@ -212,7 +212,7 @@ export async function loader({request, context}: LoaderFunctionArgs) {
212
212
  const isRegular = !url.searchParams.has('predictive');
213
213
 
214
214
  if (!isRegular) {
215
- return {}
215
+ return {};
216
216
  }
217
217
 
218
218
  const searchPromise = regularSearch({request, context});
@@ -2,7 +2,7 @@
2
2
  "name": "skeleton",
3
3
  "private": true,
4
4
  "sideEffects": false,
5
- "version": "2026.1.0",
5
+ "version": "2026.1.2",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "build": "shopify hydrogen build --codegen",
@@ -14,12 +14,12 @@
14
14
  },
15
15
  "prettier": "@shopify/prettier-config",
16
16
  "dependencies": {
17
- "@shopify/hydrogen": "2026.1.0",
17
+ "@shopify/hydrogen": "2026.1.2",
18
18
  "graphql": "^16.10.0",
19
19
  "graphql-tag": "^2.12.6",
20
20
  "isbot": "^5.1.22",
21
- "react": "18.3.1",
22
- "react-dom": "18.3.1",
21
+ "react": "^18.3.1",
22
+ "react-dom": "^18.3.1",
23
23
  "react-router": "7.12.0",
24
24
  "react-router-dom": "7.12.0"
25
25
  },
@@ -30,15 +30,15 @@
30
30
  "@graphql-codegen/cli": "5.0.2",
31
31
  "@react-router/dev": "7.12.0",
32
32
  "@react-router/fs-routes": "7.12.0",
33
- "@shopify/cli": "3.85.4",
34
- "@shopify/hydrogen-codegen": "^0.3.3",
35
- "@shopify/mini-oxygen": "^4.0.0",
33
+ "@shopify/cli": "3.91.1",
34
+ "@shopify/hydrogen-codegen": "0.3.3",
35
+ "@shopify/mini-oxygen": "4.0.1",
36
36
  "@shopify/oxygen-workers-types": "^4.1.6",
37
37
  "@shopify/prettier-config": "^1.1.2",
38
38
  "@total-typescript/ts-reset": "^0.6.1",
39
39
  "@types/eslint": "^9.6.1",
40
- "@types/react": "^18.2.22",
41
- "@types/react-dom": "^18.2.7",
40
+ "@types/react": "^18.3.28",
41
+ "@types/react-dom": "^18.3.7",
42
42
  "@typescript-eslint/eslint-plugin": "^8.21.0",
43
43
  "@typescript-eslint/parser": "^8.21.0",
44
44
  "eslint": "^9.18.0",
@@ -58,6 +58,6 @@
58
58
  "vite-tsconfig-paths": "^4.3.1"
59
59
  },
60
60
  "engines": {
61
- "node": ">=18.0.0"
61
+ "node": "^22 || ^24"
62
62
  }
63
63
  }
@@ -8,7 +8,7 @@ export default defineConfig({
8
8
  plugins: [hydrogen(), oxygen(), reactRouter(), tsconfigPaths()],
9
9
  build: {
10
10
  // Allow a strict Content-Security-Policy
11
- // withtout inlining assets as base64:
11
+ // without inlining assets as base64:
12
12
  assetsInlineLimit: 0,
13
13
  },
14
14
  ssr: {
@@ -21,7 +21,7 @@ export default defineConfig({
21
21
  ],
22
22
  build: {
23
23
  // Allow a strict Content-Security-Policy
24
- // withtout inlining assets as base64:
24
+ // without inlining assets as base64:
25
25
  assetsInlineLimit: 0,
26
26
  },
27
27
  ssr: {
@@ -11,7 +11,6 @@ import { commonFlags, overrideFlag, flagsToCamelObject, DEFAULT_INSPECTOR_PORT,
11
11
  import { spawnCodegenProcess } from '../../lib/codegen.js';
12
12
  import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
13
13
  import { displayDevUpgradeNotice } from './upgrade.js';
14
- import { checkReactRouterVersions } from '../../lib/react-router-version-check.js';
15
14
  import { getDevConfigInBackground, TUNNEL_DOMAIN, startTunnelAndPushConfig, isMockShop, notifyIssueWithTunnelAndMockShop, getUtilityBannerlines, getDebugBannerLine } from '../../lib/dev-shared.js';
16
15
  import { getCliCommand } from '../../lib/shell.js';
17
16
  import { findPort } from '../../lib/find-port.js';
@@ -238,9 +237,6 @@ async function runDev({
238
237
  viteServer.bindCLIShortcuts({ print: true });
239
238
  console.log("\n");
240
239
  const storefrontTitle = (await backgroundPromise).storefrontTitle;
241
- if (!disableVersionCheck) {
242
- await checkReactRouterVersions(root);
243
- }
244
240
  showSuccessBanner({
245
241
  disableVirtualRoutes,
246
242
  debug,
@@ -1,6 +1,6 @@
1
+ import { PackageManager } from '@shopify/cli-kit/node/node-package-manager';
1
2
  import * as _oclif_core_lib_interfaces_parser_js from '@oclif/core/lib/interfaces/parser.js';
2
3
  import Command from '@shopify/cli-kit/node/base-command';
3
- import { PackageManager } from '@shopify/cli-kit/node/node-package-manager';
4
4
 
5
5
  declare const SETUP_I18N_STRATEGIES: readonly ["subfolders", "domains", "subdomains"];
6
6
  type I18nStrategy = (typeof SETUP_I18N_STRATEGIES)[number];
@@ -24,7 +24,6 @@ type InitOptions = {
24
24
  i18n?: I18nChoice;
25
25
  token?: string;
26
26
  force?: boolean;
27
- routes?: boolean;
28
27
  shortcut?: boolean;
29
28
  installDeps?: boolean;
30
29
  git?: boolean;
@@ -41,7 +40,6 @@ declare class Init extends Command {
41
40
  static descriptionWithMarkdown: string;
42
41
  static description: string;
43
42
  static flags: {
44
- routes: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
45
43
  git: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
46
44
  quickstart: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
47
45
  'package-manager': _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
@@ -60,7 +58,7 @@ declare class Init extends Command {
60
58
  declare function runInit({ markets, ...options }?: InitOptions & {
61
59
  markets?: InitOptions['i18n'];
62
60
  }): Promise<{
63
- language?: "js" | "ts";
61
+ language?: Language;
64
62
  packageManager: "npm" | "pnpm" | "yarn" | "bun" | "unknown";
65
63
  cssStrategy?: CssStrategy;
66
64
  cliCommand: CliCommand;
@@ -1,7 +1,7 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
2
  import { Flags } from '@oclif/core';
3
3
  import { AbortError } from '@shopify/cli-kit/node/error';
4
- import { commonFlags, parseProcessFlags, flagsToCamelObject } from '../../lib/flags.js';
4
+ import { commonFlags, flagsToCamelObject, parseProcessFlags } from '../../lib/flags.js';
5
5
  import { checkCurrentCLIVersion } from '../../lib/check-cli-version.js';
6
6
  import { STYLING_CHOICES } from '../../lib/setups/css/index.js';
7
7
  import { I18N_CHOICES } from '../../lib/setups/i18n/index.js';
@@ -36,11 +36,6 @@ class Init extends Command {
36
36
  ...commonFlags.styling,
37
37
  ...commonFlags.markets,
38
38
  ...commonFlags.shortcut,
39
- routes: Flags.boolean({
40
- description: "Generate routes for all pages.",
41
- env: "SHOPIFY_HYDROGEN_FLAG_ROUTES",
42
- allowNo: true
43
- }),
44
39
  git: Flags.boolean({
45
40
  description: "Init Git and create initial commits.",
46
41
  env: "SHOPIFY_HYDROGEN_FLAG_GIT",
@@ -48,7 +43,7 @@ class Init extends Command {
48
43
  allowNo: true
49
44
  }),
50
45
  quickstart: Flags.boolean({
51
- description: "Scaffolds a new Hydrogen project with a set of sensible defaults. Equivalent to `shopify hydrogen init --path hydrogen-quickstart --mock-shop --language js --shortcut --routes --markets none`",
46
+ description: "Scaffolds a new Hydrogen project with a set of sensible defaults. Equivalent to `shopify hydrogen init --path hydrogen-quickstart --mock-shop --language js --shortcut --markets none`",
52
47
  env: "SHOPIFY_HYDROGEN_FLAG_QUICKSTART",
53
48
  default: false
54
49
  }),
@@ -91,7 +86,6 @@ async function runInit({
91
86
  options.language ??= "js";
92
87
  options.mockShop ??= true;
93
88
  options.path ??= "./hydrogen-quickstart";
94
- options.routes ??= true;
95
89
  options.shortcut ??= true;
96
90
  options.styling ??= "none";
97
91
  }
@@ -5,7 +5,7 @@ import { outputInfo } from '@shopify/cli-kit/node/output';
5
5
  import { resolvePath, joinPath } from '@shopify/cli-kit/node/path';
6
6
  import { setH2OVerbose, isH2Verbose, muteDevLogs } from '../../lib/log.js';
7
7
  import { getProjectPaths, isClassicProject } from '../../lib/remix-config.js';
8
- import { overrideFlag, commonFlags, flagsToCamelObject, DEFAULT_APP_PORT } from '../../lib/flags.js';
8
+ import { commonFlags, overrideFlag, flagsToCamelObject, DEFAULT_APP_PORT } from '../../lib/flags.js';
9
9
  import { startMiniOxygen } from '../../lib/mini-oxygen/index.js';
10
10
  import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
11
11
  import { getConfig } from '../../lib/shopify-config.js';
@@ -1,5 +1,5 @@
1
1
  import { resolvePath } from '@shopify/cli-kit/node/path';
2
- import { overrideFlag, commonFlags, flagsToCamelObject } from '../../../lib/flags.js';
2
+ import { commonFlags, overrideFlag, flagsToCamelObject } from '../../../lib/flags.js';
3
3
  import Command from '@shopify/cli-kit/node/base-command';
4
4
  import { renderSuccess, renderTasks, renderWarning } from '@shopify/cli-kit/node/ui';
5
5
  import { getPackageManager, installNodeModules } from '@shopify/cli-kit/node/node-package-manager';
@@ -5,7 +5,7 @@ import { removeFile, moveFile, readFile, writeFile, fileExists } from '@shopify/
5
5
  import { readAndParsePackageJson, installNodeModules, getPackageManager } from '@shopify/cli-kit/node/node-package-manager';
6
6
  import { commonFlags, flagsToCamelObject } from '../../../lib/flags.js';
7
7
  import { getRawRemixConfig } from '../../../lib/remix-config.js';
8
- import { mergePackageJson, replaceFileContent } from '../../../lib/file.js';
8
+ import { replaceFileContent, mergePackageJson } from '../../../lib/file.js';
9
9
  import { importLangAstGrep } from '../../../lib/ast.js';
10
10
  import { getAssetsDir } from '../../../lib/build.js';
11
11
  import { getCodeFormatOptions, formatCode } from '../../../lib/format-code.js';
@@ -3,7 +3,7 @@ import { AbortController } from '@shopify/cli-kit/node/abort';
3
3
  import { renderTasks } from '@shopify/cli-kit/node/ui';
4
4
  import { resolvePath, basename, joinPath } from '@shopify/cli-kit/node/path';
5
5
  import { fileExists, glob, copyFile } from '@shopify/cli-kit/node/fs';
6
- import { overrideFlag, commonFlags, flagsToCamelObject } from '../../lib/flags.js';
6
+ import { commonFlags, overrideFlag, flagsToCamelObject } from '../../lib/flags.js';
7
7
  import { renderI18nPrompt, setupI18nStrategy } from '../../lib/setups/i18n/index.js';
8
8
  import { getRemixConfig } from '../../lib/remix-config.js';
9
9
  import { handleRouteGeneration, generateProjectEntries, handleCliShortcut, renderProjectReady } from '../../lib/onboarding/common.js';
@@ -49,39 +49,37 @@ async function runSetup(options) {
49
49
  extraChoices: { none: "Set up later" }
50
50
  });
51
51
  const i18n = i18nStrategy === "none" ? void 0 : i18nStrategy;
52
- const { needsRouteGeneration, setupRoutes } = await handleRouteGeneration(controller);
52
+ const { setupRoutes } = handleRouteGeneration(controller);
53
53
  let routes;
54
- if (needsRouteGeneration) {
55
- const templateRoot = await getTemplateAppFile("..");
56
- const [typescript, dtsFiles] = await Promise.all([
57
- fileExists(joinPath(rootDirectory, "tsconfig.json")),
58
- glob("*.d.ts", { cwd: templateRoot })
59
- ]);
60
- backgroundWorkPromise = backgroundWorkPromise.then(
61
- () => Promise.all([
62
- ...dtsFiles.map(
63
- (filename) => copyFile(
64
- joinPath(templateRoot, filename),
65
- resolvePath(rootDirectory, filename)
66
- )
67
- ),
68
- // Copy app entries
69
- generateProjectEntries({
70
- rootDirectory,
71
- appDirectory,
72
- typescript
73
- })
74
- ])
75
- ).then(async () => {
76
- routes = await setupRoutes(rootDirectory, typescript ? "ts" : "js", {
77
- i18nStrategy: i18n,
78
- // User might have added files before running this command.
79
- // We should overwrite them to ensure the routes are set up correctly.
80
- // Relies on Git to restore the files if needed.
81
- overwriteFileDeps: true
82
- });
54
+ const templateRoot = await getTemplateAppFile("..");
55
+ const [typescript, dtsFiles] = await Promise.all([
56
+ fileExists(joinPath(rootDirectory, "tsconfig.json")),
57
+ glob("*.d.ts", { cwd: templateRoot })
58
+ ]);
59
+ backgroundWorkPromise = backgroundWorkPromise.then(
60
+ () => Promise.all([
61
+ ...dtsFiles.map(
62
+ (filename) => copyFile(
63
+ joinPath(templateRoot, filename),
64
+ resolvePath(rootDirectory, filename)
65
+ )
66
+ ),
67
+ // Copy app entries
68
+ generateProjectEntries({
69
+ rootDirectory,
70
+ appDirectory,
71
+ typescript
72
+ })
73
+ ])
74
+ ).then(async () => {
75
+ routes = await setupRoutes(rootDirectory, typescript ? "ts" : "js", {
76
+ i18nStrategy: i18n,
77
+ // User might have added files before running this command.
78
+ // We should overwrite them to ensure the routes are set up correctly.
79
+ // Relies on Git to restore the files if needed.
80
+ overwriteFileDeps: true
83
81
  });
84
- }
82
+ });
85
83
  if (i18n) {
86
84
  backgroundWorkPromise = backgroundWorkPromise.then(
87
85
  () => setupI18nStrategy(i18n, { rootDirectory })
@@ -93,7 +91,7 @@ async function runSetup(options) {
93
91
  cliCommand,
94
92
  options.shortcut
95
93
  );
96
- if (!i18n && !needsRouteGeneration && !createShortcut) return;
94
+ if (!i18n && !createShortcut) return;
97
95
  if (createShortcut) {
98
96
  backgroundWorkPromise = backgroundWorkPromise.then(async () => {
99
97
  if (await createShortcut()) {
@@ -859,6 +859,13 @@ async function displayDevUpgradeNotice({
859
859
  const { currentVersion, currentDependencies } = await getHydrogenVersion({
860
860
  appPath
861
861
  });
862
+ if (currentVersion.startsWith("workspace:")) {
863
+ renderInfo({
864
+ headline: "Using monorepo @shopify/hydrogen dependency",
865
+ body: "This project uses the workspace protocol for @shopify/hydrogen, so upgrade notices are skipped during local monorepo development."
866
+ });
867
+ return;
868
+ }
862
869
  const isPrerelease = semver.prerelease(currentVersion);
863
870
  if (isPrerelease || /^[a-z]+$/i.test(currentVersion)) {
864
871
  return;
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
- const { stdout } = await execAsync("npm root");
73
- let nodeModulesPath = stdout.trim();
74
- if (!nodeModulesPath && isHydrogenMonorepo) {
75
- nodeModulesPath = joinPath(dirname(monorepoPackagesPath), "node_modules");
72
+ if (isHydrogenMonorepo) {
73
+ return getSkeletonNodeModules();
76
74
  }
77
- return nodeModulesPath;
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 };
@@ -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, resolvePath, joinPath, basename } from '@shopify/cli-kit/node/path';
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;
@@ -1,5 +1,5 @@
1
1
  import { extname } from '@shopify/cli-kit/node/path';
2
- import * as prettier from 'prettier';
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 prettier.resolveConfig(pathToUse) || DEFAULT_PRETTIER_CONFIG;
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 prettier.format(content, {
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.