@shopify/cli-hydrogen 5.1.2 → 5.2.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.
Files changed (73) hide show
  1. package/dist/commands/hydrogen/build.js +4 -1
  2. package/dist/commands/hydrogen/dev.js +25 -17
  3. package/dist/commands/hydrogen/generate/route.test.js +0 -1
  4. package/dist/commands/hydrogen/init.js +6 -3
  5. package/dist/commands/hydrogen/init.test.js +2 -0
  6. package/dist/commands/hydrogen/preview.js +2 -2
  7. package/dist/commands/hydrogen/setup.js +3 -0
  8. package/dist/generator-templates/starter/app/components/Footer.tsx +1 -1
  9. package/dist/generator-templates/starter/app/components/Header.tsx +1 -1
  10. package/dist/generator-templates/starter/app/components/Search.tsx +3 -3
  11. package/dist/generator-templates/starter/app/entry.server.tsx +9 -1
  12. package/dist/generator-templates/starter/app/root.tsx +31 -5
  13. package/dist/generator-templates/starter/app/routes/$.tsx +4 -0
  14. package/dist/generator-templates/starter/app/routes/_index.tsx +6 -2
  15. package/dist/generator-templates/starter/app/routes/account.$.tsx +1 -2
  16. package/dist/generator-templates/starter/app/routes/account.addresses.tsx +1 -1
  17. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +2 -7
  18. package/dist/generator-templates/starter/app/routes/account.profile.tsx +7 -2
  19. package/dist/generator-templates/starter/app/routes/account.tsx +4 -3
  20. package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +6 -2
  21. package/dist/generator-templates/starter/app/routes/account_.login.tsx +6 -2
  22. package/dist/generator-templates/starter/app/routes/account_.logout.tsx +2 -6
  23. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +1 -2
  24. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle._index.tsx +1 -2
  25. package/dist/generator-templates/starter/app/routes/blogs._index.tsx +2 -3
  26. package/dist/generator-templates/starter/app/routes/cart.tsx +1 -2
  27. package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +1 -2
  28. package/dist/generator-templates/starter/app/routes/pages.$handle.tsx +1 -2
  29. package/dist/generator-templates/starter/app/routes/policies.$handle.tsx +2 -3
  30. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +23 -15
  31. package/dist/generator-templates/starter/app/routes/search.tsx +1 -2
  32. package/dist/generator-templates/starter/package.json +5 -5
  33. package/dist/generator-templates/starter/remix.config.js +1 -0
  34. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +9 -9
  35. package/dist/generator-templates/starter/tsconfig.json +1 -0
  36. package/dist/lib/ast.js +9 -0
  37. package/dist/lib/check-version.test.js +1 -0
  38. package/dist/lib/codegen.js +17 -7
  39. package/dist/lib/environment-variables.js +15 -11
  40. package/dist/lib/file.js +1 -1
  41. package/dist/lib/find-port.js +9 -0
  42. package/dist/lib/flags.js +6 -5
  43. package/dist/lib/format-code.js +7 -4
  44. package/dist/lib/graphql/admin/client.js +18 -0
  45. package/dist/lib/graphql/admin/client.test.js +28 -3
  46. package/dist/lib/live-reload.js +62 -0
  47. package/dist/lib/log.js +6 -1
  48. package/dist/lib/mini-oxygen.js +28 -18
  49. package/dist/lib/missing-routes.js +17 -1
  50. package/dist/lib/onboarding/common.js +5 -0
  51. package/dist/lib/onboarding/local.js +21 -8
  52. package/dist/lib/remix-config.js +2 -0
  53. package/dist/lib/remix-version-check.test.js +1 -0
  54. package/dist/lib/setups/css/index.js +4 -2
  55. package/dist/lib/setups/css/replacers.js +7 -4
  56. package/dist/lib/setups/i18n/replacers.js +7 -5
  57. package/dist/lib/setups/routes/generate.js +15 -29
  58. package/dist/lib/setups/routes/generate.test.js +1 -3
  59. package/dist/lib/template-downloader.js +4 -0
  60. package/dist/lib/transpile-ts.js +5 -3
  61. package/dist/lib/virtual-routes.js +4 -1
  62. package/dist/virtual-routes/components/HydrogenLogoBaseBW.jsx +29 -4
  63. package/dist/virtual-routes/components/HydrogenLogoBaseColor.jsx +44 -10
  64. package/dist/virtual-routes/components/IconBanner.jsx +289 -44
  65. package/dist/virtual-routes/components/IconDiscord.jsx +18 -1
  66. package/dist/virtual-routes/components/IconError.jsx +58 -17
  67. package/dist/virtual-routes/components/IconGithub.jsx +20 -1
  68. package/dist/virtual-routes/components/IconTwitter.jsx +18 -1
  69. package/dist/virtual-routes/components/Layout.jsx +2 -1
  70. package/dist/virtual-routes/routes/index.jsx +199 -94
  71. package/dist/virtual-routes/virtual-root.jsx +62 -16
  72. package/oclif.manifest.json +3 -3
  73. package/package.json +8 -7
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import Command from '@shopify/cli-kit/node/base-command';
3
3
  import { outputInfo, outputContent, outputToken, outputWarn } from '@shopify/cli-kit/node/output';
4
- import { rmdir, fileSize, glob, removeFile, copyFile } from '@shopify/cli-kit/node/fs';
4
+ import { rmdir, fileSize, glob, removeFile, fileExists, copyFile } from '@shopify/cli-kit/node/fs';
5
5
  import { resolvePath, relativePath, joinPath } from '@shopify/cli-kit/node/path';
6
6
  import { getPackageManager } from '@shopify/cli-kit/node/node-package-manager';
7
7
  import colors from '@shopify/cli-kit/node/colors';
@@ -130,6 +130,9 @@ This build is missing ${missingRoutes.length} route${missingRoutes.length > 1 ?
130
130
  }
131
131
  }
132
132
  async function copyPublicFiles(publicPath, buildPathClient) {
133
+ if (!await fileExists(publicPath)) {
134
+ return;
135
+ }
133
136
  return copyFile(publicPath, buildPathClient);
134
137
  }
135
138
 
@@ -6,8 +6,8 @@ import { renderFatalError } from '@shopify/cli-kit/node/ui';
6
6
  import colors from '@shopify/cli-kit/node/colors';
7
7
  import { copyPublicFiles } from './build.js';
8
8
  import { getProjectPaths, assertOxygenChecks, getRemixConfig } from '../../lib/remix-config.js';
9
- import { muteDevLogs, muteRemixLogs, createRemixLogger, enhanceH2Logs } from '../../lib/log.js';
10
- import { commonFlags, deprecated, flagsToCamelObject } from '../../lib/flags.js';
9
+ import { muteDevLogs, createRemixLogger, enhanceH2Logs } from '../../lib/log.js';
10
+ import { commonFlags, deprecated, flagsToCamelObject, DEFAULT_PORT } from '../../lib/flags.js';
11
11
  import Command from '@shopify/cli-kit/node/base-command';
12
12
  import { Flags } from '@oclif/core';
13
13
  import { startMiniOxygen } from '../../lib/mini-oxygen.js';
@@ -16,6 +16,7 @@ import { addVirtualRoutes } from '../../lib/virtual-routes.js';
16
16
  import { spawnCodegenProcess } from '../../lib/codegen.js';
17
17
  import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
18
18
  import { getConfig } from '../../lib/shopify-config.js';
19
+ import { setupLiveReload } from '../../lib/live-reload.js';
19
20
  import { checkRemixVersions } from '../../lib/remix-version-check.js';
20
21
 
21
22
  const LOG_REBUILDING = "\u{1F9F1} Rebuilding...";
@@ -56,7 +57,7 @@ class Dev extends Command {
56
57
  }
57
58
  }
58
59
  async function runDev({
59
- port,
60
+ port: portFlag = DEFAULT_PORT,
60
61
  path: appPath,
61
62
  useCodegen = false,
62
63
  codegenConfigPath,
@@ -68,7 +69,6 @@ async function runDev({
68
69
  if (!process.env.NODE_ENV)
69
70
  process.env.NODE_ENV = "development";
70
71
  muteDevLogs();
71
- await muteRemixLogs();
72
72
  if (debug)
73
73
  (await import('node:inspector')).open();
74
74
  const { root, publicPath, buildPathClient, buildPathWorkerFile } = getProjectPaths(appPath);
@@ -102,14 +102,15 @@ async function runDev({
102
102
  let isInitialBuild = true;
103
103
  let initialBuildDurationMs = 0;
104
104
  let initialBuildStartTimeMs = Date.now();
105
+ const liveReload = remixConfig.future.v2_dev ? await setupLiveReload(remixConfig.devServerPort) : void 0;
105
106
  let miniOxygen;
106
107
  async function safeStartMiniOxygen() {
107
108
  if (miniOxygen)
108
109
  return;
109
110
  miniOxygen = await startMiniOxygen({
110
111
  root,
111
- port,
112
- watch: true,
112
+ port: portFlag,
113
+ watch: !liveReload,
113
114
  buildPathWorkerFile,
114
115
  buildPathClient,
115
116
  env: await envPromise
@@ -145,13 +146,15 @@ View GraphiQL API browser: ${graphiqlUrl}`)]
145
146
  },
146
147
  {
147
148
  reloadConfig,
148
- onBuildStart() {
149
+ onBuildStart(ctx) {
149
150
  if (!isInitialBuild && !skipRebuildLogs) {
150
151
  outputInfo(LOG_REBUILDING);
151
152
  console.time(LOG_REBUILT);
152
153
  }
154
+ liveReload?.onBuildStart(ctx);
153
155
  },
154
- async onBuildFinish() {
156
+ onBuildManifest: liveReload?.onBuildManifest,
157
+ async onBuildFinish(context, duration, succeeded) {
155
158
  if (isInitialBuild) {
156
159
  await copyingFiles;
157
160
  initialBuildDurationMs = Date.now() - initialBuildStartTimeMs;
@@ -162,16 +165,21 @@ View GraphiQL API browser: ${graphiqlUrl}`)]
162
165
  if (!miniOxygen)
163
166
  console.log("");
164
167
  }
165
- if (!miniOxygen) {
166
- if (!await serverBundleExists()) {
167
- return renderFatalError({
168
- name: "BuildError",
169
- type: 0,
170
- message: "MiniOxygen cannot start because the server bundle has not been generated.",
171
- 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."
172
- });
168
+ if (!miniOxygen && !await serverBundleExists()) {
169
+ return renderFatalError({
170
+ name: "BuildError",
171
+ type: 0,
172
+ message: "MiniOxygen cannot start because the server bundle has not been generated.",
173
+ 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."
174
+ });
175
+ }
176
+ if (succeeded) {
177
+ if (!miniOxygen) {
178
+ await safeStartMiniOxygen();
179
+ } else if (liveReload) {
180
+ await miniOxygen.reload({ worker: true });
173
181
  }
174
- await safeStartMiniOxygen();
182
+ liveReload?.onAppReady(context);
175
183
  }
176
184
  },
177
185
  async onFileCreated(file) {
@@ -16,7 +16,6 @@ describe("runGenerate", () => {
16
16
  it("calls route generation and renders the result", async () => {
17
17
  vi.mocked(generateRoutes).mockResolvedValue({
18
18
  isTypescript: true,
19
- transpilerOptions: {},
20
19
  formatOptions: {},
21
20
  v2Flags: {},
22
21
  routeGroups: {},
@@ -6,7 +6,7 @@ import { AbortError } from '@shopify/cli-kit/node/error';
6
6
  import { AbortController } from '@shopify/cli-kit/node/abort';
7
7
  import { commonFlags, flagsToCamelObject, parseProcessFlags } from '../../lib/flags.js';
8
8
  import { checkHydrogenVersion } from '../../lib/check-version.js';
9
- import { SETUP_CSS_STRATEGIES } from './../../lib/setups/css/index.js';
9
+ import { STYLING_CHOICES } from './../../lib/setups/css/index.js';
10
10
  import { I18N_CHOICES } from '../../lib/setups/i18n/index.js';
11
11
  import { supressNodeExperimentalWarnings } from '../../lib/process.js';
12
12
  import { setupRemoteTemplate, setupLocalStarterTemplate } from '../../lib/onboarding/index.js';
@@ -58,9 +58,9 @@ class Init extends Command {
58
58
  `Invalid URL structure strategy: ${flags.markets}. Must be one of ${I18N_CHOICES.join(", ")}`
59
59
  );
60
60
  }
61
- if (flags.styling && !SETUP_CSS_STRATEGIES.includes(flags.styling)) {
61
+ if (flags.styling && !STYLING_CHOICES.includes(flags.styling)) {
62
62
  throw new AbortError(
63
- `Invalid styling strategy: ${flags.styling}. Must be one of ${SETUP_CSS_STRATEGIES.join(", ")}`
63
+ `Invalid styling strategy: ${flags.styling}. Must be one of ${STYLING_CHOICES.join(", ")}`
64
64
  );
65
65
  }
66
66
  await runInit(flagsToCamelObject(flags));
@@ -70,6 +70,9 @@ async function runInit(options = parseProcessFlags(process.argv, FLAG_MAP)) {
70
70
  supressNodeExperimentalWarnings();
71
71
  options.git ??= true;
72
72
  const showUpgrade = await checkHydrogenVersion(
73
+ // Resolving the CLI package from a local directory might fail because
74
+ // this code could be run from a global dependency (e.g. on `npm create`).
75
+ // Therefore, pass the known path to the package.json directly from here:
73
76
  fileURLToPath(new URL("../../../package.json", import.meta.url)),
74
77
  "cli"
75
78
  );
@@ -145,6 +145,7 @@ describe("init", () => {
145
145
  expect(output).toMatch("Help");
146
146
  expect(output).toMatch("Next steps");
147
147
  expect(output).toMatch(
148
+ // Output contains banner characters. USe [^\w]*? to match them.
148
149
  /Run `cd .*? &&[^\w]*?npm[^\w]*?install[^\w]*?&&[^\w]*?npm[^\w]*?run[^\w]*?dev`/ims
149
150
  );
150
151
  });
@@ -220,6 +221,7 @@ describe("init", () => {
220
221
  expect(output).toMatch("Help");
221
222
  expect(output).toMatch("Next steps");
222
223
  expect(output).toMatch(
224
+ // Output contains banner characters. USe [^\w]*? to match them.
223
225
  /Run `cd .*? &&[^\w]*?npm[^\w]*?install[^\w]*?&&[^\w]*?npm[^\w]*?run[^\w]*?dev`/ims
224
226
  );
225
227
  });
@@ -1,7 +1,7 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
2
  import { muteDevLogs } from '../../lib/log.js';
3
3
  import { getProjectPaths } from '../../lib/remix-config.js';
4
- import { commonFlags } from '../../lib/flags.js';
4
+ import { commonFlags, DEFAULT_PORT } from '../../lib/flags.js';
5
5
  import { startMiniOxygen } from '../../lib/mini-oxygen.js';
6
6
 
7
7
  class Preview extends Command {
@@ -16,7 +16,7 @@ class Preview extends Command {
16
16
  }
17
17
  }
18
18
  async function runPreview({
19
- port,
19
+ port = DEFAULT_PORT,
20
20
  path: appPath
21
21
  }) {
22
22
  if (!process.env.NODE_ENV)
@@ -57,6 +57,8 @@ async function runSetup(options) {
57
57
  const typescript = !!remixConfig.tsconfigPath;
58
58
  backgroundWorkPromise = backgroundWorkPromise.then(
59
59
  () => Promise.all([
60
+ // When starting from hello-world, the server entry point won't
61
+ // include all the cart logic from skeleton, so we need to copy it.
60
62
  generateProjectFile("../server.ts", { ...remixConfig, typescript }),
61
63
  ...typescript ? [
62
64
  copyFile(
@@ -71,6 +73,7 @@ async function runSetup(options) {
71
73
  )
72
74
  )
73
75
  ] : [],
76
+ // Copy app entries
74
77
  generateProjectEntries({
75
78
  rootDirectory: remixConfig.rootDirectory,
76
79
  appDirectory: remixConfig.appDirectory,
@@ -93,7 +93,7 @@ function activeLinkStyle({
93
93
  isPending: boolean;
94
94
  }) {
95
95
  return {
96
- fontWeight: isActive ? 'bold' : '',
96
+ fontWeight: isActive ? 'bold' : undefined,
97
97
  color: isPending ? 'grey' : 'white',
98
98
  };
99
99
  }
@@ -172,7 +172,7 @@ function activeLinkStyle({
172
172
  isPending: boolean;
173
173
  }) {
174
174
  return {
175
- fontWeight: isActive ? 'bold' : '',
175
+ fontWeight: isActive ? 'bold' : undefined,
176
176
  color: isPending ? 'grey' : 'black',
177
177
  };
178
178
  }
@@ -1,13 +1,13 @@
1
1
  import {
2
- useParams,
3
- useFetcher,
4
2
  Link,
5
3
  Form,
4
+ useParams,
5
+ useFetcher,
6
+ useFetchers,
6
7
  type FormProps,
7
8
  } from '@remix-run/react';
8
9
  import {Image, Money, Pagination} from '@shopify/hydrogen';
9
10
  import React, {useRef, useEffect} from 'react';
10
- import {useFetchers} from '@remix-run/react';
11
11
 
12
12
  import type {
13
13
  PredictiveProductFragment,
@@ -2,6 +2,7 @@ import type {EntryContext} from '@shopify/remix-oxygen';
2
2
  import {RemixServer} from '@remix-run/react';
3
3
  import isbot from 'isbot';
4
4
  import {renderToReadableStream} from 'react-dom/server';
5
+ import {createContentSecurityPolicy} from '@shopify/hydrogen';
5
6
 
6
7
  export default async function handleRequest(
7
8
  request: Request,
@@ -9,9 +10,14 @@ export default async function handleRequest(
9
10
  responseHeaders: Headers,
10
11
  remixContext: EntryContext,
11
12
  ) {
13
+ const {nonce, header, NonceProvider} = createContentSecurityPolicy();
14
+
12
15
  const body = await renderToReadableStream(
13
- <RemixServer context={remixContext} url={request.url} />,
16
+ <NonceProvider>
17
+ <RemixServer context={remixContext} url={request.url} />
18
+ </NonceProvider>,
14
19
  {
20
+ nonce,
15
21
  signal: request.signal,
16
22
  onError(error) {
17
23
  // eslint-disable-next-line no-console
@@ -26,6 +32,8 @@ export default async function handleRequest(
26
32
  }
27
33
 
28
34
  responseHeaders.set('Content-Type', 'text/html');
35
+ responseHeaders.set('Content-Security-Policy', header);
36
+
29
37
  return new Response(body, {
30
38
  headers: responseHeaders,
31
39
  status: responseStatusCode,
@@ -1,3 +1,4 @@
1
+ import {useNonce} from '@shopify/hydrogen';
1
2
  import {defer, type LoaderArgs} from '@shopify/remix-oxygen';
2
3
  import {
3
4
  Links,
@@ -5,19 +6,40 @@ import {
5
6
  Outlet,
6
7
  Scripts,
7
8
  useCatch,
9
+ LiveReload,
8
10
  useMatches,
9
11
  useRouteError,
10
12
  useLoaderData,
11
13
  ScrollRestoration,
12
14
  isRouteErrorResponse,
15
+ type ShouldRevalidateFunction,
13
16
  } from '@remix-run/react';
14
- import type {CustomerAccessToken} from '@shopify/hydrogen-react/storefront-api-types';
17
+ import type {CustomerAccessToken} from '@shopify/hydrogen/storefront-api-types';
15
18
  import type {HydrogenSession} from '../server';
16
19
  import favicon from '../public/favicon.svg';
17
20
  import resetStyles from './styles/reset.css';
18
21
  import appStyles from './styles/app.css';
19
22
  import {Layout} from '~/components/Layout';
20
23
 
24
+ // This is important to avoid re-fetching root queries on sub-navigations
25
+ export const shouldRevalidate: ShouldRevalidateFunction = ({
26
+ formMethod,
27
+ currentUrl,
28
+ nextUrl,
29
+ }) => {
30
+ // revalidate when a mutation is performed e.g add to cart, login...
31
+ if (formMethod && formMethod !== 'GET') {
32
+ return true;
33
+ }
34
+
35
+ // revalidate when manually revalidating via useRevalidator
36
+ if (currentUrl.toString() === nextUrl.toString()) {
37
+ return true;
38
+ }
39
+
40
+ return false;
41
+ };
42
+
21
43
  export function links() {
22
44
  return [
23
45
  {rel: 'stylesheet', href: resetStyles},
@@ -77,6 +99,7 @@ export async function loader({context}: LoaderArgs) {
77
99
  }
78
100
 
79
101
  export default function App() {
102
+ const nonce = useNonce();
80
103
  const data = useLoaderData<typeof loader>();
81
104
 
82
105
  return (
@@ -91,8 +114,9 @@ export default function App() {
91
114
  <Layout {...data}>
92
115
  <Outlet />
93
116
  </Layout>
94
- <ScrollRestoration />
95
- <Scripts />
117
+ <ScrollRestoration nonce={nonce} />
118
+ <Scripts nonce={nonce} />
119
+ <LiveReload nonce={nonce} />
96
120
  </body>
97
121
  </html>
98
122
  );
@@ -101,6 +125,7 @@ export default function App() {
101
125
  export function ErrorBoundary() {
102
126
  const error = useRouteError();
103
127
  const [root] = useMatches();
128
+ const nonce = useNonce();
104
129
  let errorMessage = 'Unknown error';
105
130
  let errorStatus = 500;
106
131
 
@@ -131,8 +156,9 @@ export function ErrorBoundary() {
131
156
  )}
132
157
  </div>
133
158
  </Layout>
134
- <ScrollRestoration />
135
- <Scripts />
159
+ <ScrollRestoration nonce={nonce} />
160
+ <Scripts nonce={nonce} />
161
+ <LiveReload nonce={nonce} />
136
162
  </body>
137
163
  </html>
138
164
  );
@@ -5,3 +5,7 @@ export async function loader({request}: LoaderArgs) {
5
5
  status: 404,
6
6
  });
7
7
  }
8
+
9
+ export default function CatchAllPage() {
10
+ return null;
11
+ }
@@ -1,6 +1,10 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {defer, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {Await, useLoaderData, Link} from '@remix-run/react';
2
+ import {
3
+ Await,
4
+ useLoaderData,
5
+ Link,
6
+ type V2_MetaFunction,
7
+ } from '@remix-run/react';
4
8
  import {Suspense} from 'react';
5
9
  import {Image, Money} from '@shopify/hydrogen';
6
10
  import type {
@@ -1,5 +1,4 @@
1
- import type {LoaderArgs} from '@shopify/remix-oxygen';
2
- import {redirect} from '@shopify/remix-oxygen';
1
+ import {redirect, type LoaderArgs} from '@shopify/remix-oxygen';
3
2
 
4
3
  export async function loader({context}: LoaderArgs) {
5
4
  if (await context.session.get('customerAccessToken')) {
@@ -5,13 +5,13 @@ import {
5
5
  redirect,
6
6
  type ActionArgs,
7
7
  type LoaderArgs,
8
- type V2_MetaFunction,
9
8
  } from '@shopify/remix-oxygen';
10
9
  import {
11
10
  Form,
12
11
  useActionData,
13
12
  useNavigation,
14
13
  useOutletContext,
14
+ type V2_MetaFunction,
15
15
  } from '@remix-run/react';
16
16
 
17
17
  export type ActionResponse = {
@@ -1,11 +1,6 @@
1
- import {Link, useLoaderData} from '@remix-run/react';
1
+ import {Link, useLoaderData, type V2_MetaFunction} from '@remix-run/react';
2
2
  import {Money, Pagination, getPaginationVariables} from '@shopify/hydrogen';
3
- import {
4
- json,
5
- redirect,
6
- type LoaderArgs,
7
- type V2_MetaFunction,
8
- } from '@shopify/remix-oxygen';
3
+ import {json, redirect, type LoaderArgs} from '@shopify/remix-oxygen';
9
4
  import type {
10
5
  CustomerOrdersFragment,
11
6
  OrderItemFragment,
@@ -1,12 +1,17 @@
1
1
  import type {CustomerFragment} from 'storefrontapi.generated';
2
2
  import type {CustomerUpdateInput} from '@shopify/hydrogen/storefront-api-types';
3
- import type {ActionArgs, LoaderArgs} from '@shopify/remix-oxygen';
4
- import {json, redirect, type V2_MetaFunction} from '@shopify/remix-oxygen';
3
+ import {
4
+ json,
5
+ redirect,
6
+ type ActionArgs,
7
+ type LoaderArgs,
8
+ } from '@shopify/remix-oxygen';
5
9
  import {
6
10
  Form,
7
11
  useActionData,
8
12
  useNavigation,
9
13
  useOutletContext,
14
+ type V2_MetaFunction,
10
15
  } from '@remix-run/react';
11
16
 
12
17
  export type ActionResponse = {
@@ -109,13 +109,13 @@ function AccountLayout({
109
109
  <div className="account">
110
110
  <h1>{heading}</h1>
111
111
  <br />
112
- <AcccountMenu />
112
+ <AccountMenu />
113
113
  {children}
114
114
  </div>
115
115
  );
116
116
  }
117
117
 
118
- function AcccountMenu() {
118
+ function AccountMenu() {
119
119
  function isActiveStyle({
120
120
  isActive,
121
121
  isPending,
@@ -124,10 +124,11 @@ function AcccountMenu() {
124
124
  isPending: boolean;
125
125
  }) {
126
126
  return {
127
- fontWeight: isActive ? 'bold' : '',
127
+ fontWeight: isActive ? 'bold' : undefined,
128
128
  color: isPending ? 'grey' : 'black',
129
129
  };
130
130
  }
131
+
131
132
  return (
132
133
  <nav role="navigation">
133
134
  <NavLink to="/account/orders" style={isActiveStyle}>
@@ -1,5 +1,9 @@
1
- import type {ActionArgs, LoaderArgs} from '@shopify/remix-oxygen';
2
- import {json, redirect} from '@shopify/remix-oxygen';
1
+ import {
2
+ json,
3
+ redirect,
4
+ type ActionArgs,
5
+ type LoaderArgs,
6
+ } from '@shopify/remix-oxygen';
3
7
  import {Form, useActionData, type V2_MetaFunction} from '@remix-run/react';
4
8
 
5
9
  type ActionResponse = {
@@ -3,9 +3,13 @@ import {
3
3
  redirect,
4
4
  type ActionArgs,
5
5
  type LoaderArgs,
6
- type V2_MetaFunction,
7
6
  } from '@shopify/remix-oxygen';
8
- import {Form, Link, useActionData} from '@remix-run/react';
7
+ import {
8
+ Form,
9
+ Link,
10
+ useActionData,
11
+ type V2_MetaFunction,
12
+ } from '@remix-run/react';
9
13
 
10
14
  type ActionResponse = {
11
15
  error: string | null;
@@ -1,9 +1,5 @@
1
- import {
2
- json,
3
- redirect,
4
- type ActionArgs,
5
- type V2_MetaFunction,
6
- } from '@shopify/remix-oxygen';
1
+ import {json, redirect, type ActionArgs} from '@shopify/remix-oxygen';
2
+ import {type V2_MetaFunction} from '@remix-run/react';
7
3
 
8
4
  export const meta: V2_MetaFunction = () => {
9
5
  return [{title: 'Logout'}];
@@ -1,6 +1,5 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {useLoaderData} from '@remix-run/react';
2
+ import {useLoaderData, type V2_MetaFunction} from '@remix-run/react';
4
3
  import {Image} from '@shopify/hydrogen';
5
4
 
6
5
  export const meta: V2_MetaFunction = ({data}) => {
@@ -1,6 +1,5 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {Link, useLoaderData} from '@remix-run/react';
2
+ import {Link, useLoaderData, type V2_MetaFunction} from '@remix-run/react';
4
3
  import {Image, Pagination, getPaginationVariables} from '@shopify/hydrogen';
5
4
  import type {ArticleItemFragment} from 'storefrontapi.generated';
6
5
 
@@ -1,10 +1,9 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {Link, useLoaderData} from '@remix-run/react';
2
+ import {Link, useLoaderData, type V2_MetaFunction} from '@remix-run/react';
4
3
  import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
5
4
 
6
5
  export const meta: V2_MetaFunction = () => {
7
- return [{title: `Hydrogen | Logs`}];
6
+ return [{title: `Hydrogen | Blogs`}];
8
7
  };
9
8
 
10
9
  export const loader = async ({request, context: {storefront}}: LoaderArgs) => {
@@ -1,8 +1,7 @@
1
- import {Await, useMatches} from '@remix-run/react';
1
+ import {Await, useMatches, type V2_MetaFunction} from '@remix-run/react';
2
2
  import {Suspense} from 'react';
3
3
  import type {CartQueryData} from '@shopify/hydrogen';
4
4
  import {CartForm} from '@shopify/hydrogen';
5
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
6
5
  import {type ActionArgs, json} from '@shopify/remix-oxygen';
7
6
  import type {CartApiQueryFragment} from 'storefrontapi.generated';
8
7
  import {CartMain} from '~/components/Cart';
@@ -1,6 +1,5 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, redirect, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {useLoaderData, Link} from '@remix-run/react';
2
+ import {useLoaderData, Link, type V2_MetaFunction} from '@remix-run/react';
4
3
  import {
5
4
  Pagination,
6
5
  getPaginationVariables,
@@ -1,6 +1,5 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {useLoaderData} from '@remix-run/react';
2
+ import {useLoaderData, type V2_MetaFunction} from '@remix-run/react';
4
3
 
5
4
  export const meta: V2_MetaFunction = ({data}) => {
6
5
  return [{title: `Hydrogen | ${data.page.title}`}];
@@ -1,7 +1,6 @@
1
- import type {V2_MetaFunction} from '@shopify/remix-oxygen';
2
1
  import {json, type LoaderArgs} from '@shopify/remix-oxygen';
3
- import {Link, useLoaderData} from '@remix-run/react';
4
- import {type Shop} from '@shopify/hydrogen-react/storefront-api-types';
2
+ import {Link, useLoaderData, type V2_MetaFunction} from '@remix-run/react';
3
+ import {type Shop} from '@shopify/hydrogen/storefront-api-types';
5
4
 
6
5
  type SelectedPolicies = keyof Pick<
7
6
  Shop,