@shopify/cli 3.61.0 → 3.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/hydrogen/starter/.eslintrc.cjs +1 -0
- package/dist/assets/hydrogen/starter/CHANGELOG.md +12 -74
- package/dist/assets/hydrogen/starter/app/components/Footer.tsx +3 -3
- package/dist/assets/hydrogen/starter/app/components/PageLayout.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/root.tsx +77 -37
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +62 -25
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +32 -6
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +36 -10
- package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +35 -12
- package/dist/assets/hydrogen/starter/app/routes/collections.$handle.tsx +40 -7
- package/dist/assets/hydrogen/starter/app/routes/collections._index.tsx +32 -6
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +31 -6
- package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +36 -8
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +50 -11
- package/dist/assets/hydrogen/starter/package.json +6 -7
- package/dist/assets/hydrogen/virtual-routes/components/RequestDetails.jsx +1 -2
- package/dist/assets/hydrogen/virtual-routes/components/RequestTable.jsx +1 -2
- package/dist/assets/hydrogen/virtual-routes/routes/index.jsx +1 -2
- package/dist/{chunk-LXXUWZRO.js → chunk-2OLSNRWX.js} +2 -2
- package/dist/{chunk-FFHJRSIP.js → chunk-4IJQUE7S.js} +1 -1
- package/dist/{chunk-2RKUO75O.js → chunk-4L5RRXWK.js} +129 -124
- package/dist/{chunk-75BJ33EP.js → chunk-5AOK2Y6Y.js} +2 -2
- package/dist/{chunk-4IXC46ZA.js → chunk-5CMD3IOB.js} +4 -4
- package/dist/{chunk-QX3YP6O5.js → chunk-5KRK4DLX.js} +2598 -795
- package/dist/{chunk-463OPQAS.js → chunk-72B3OWJW.js} +1 -1
- package/dist/{chunk-FWKRA64T.js → chunk-APKJSJ7J.js} +3 -3
- package/dist/{chunk-Q7PY7LVL.js → chunk-BV7GMWB6.js} +3 -3
- package/dist/{chunk-ABZKHSZ5.js → chunk-CJDUY6SJ.js} +1 -1
- package/dist/{chunk-7YJH7P7B.js → chunk-CWYZA7C7.js} +1 -1
- package/dist/{chunk-AL4KPZUN.js → chunk-CZ3HSQWY.js} +2 -2
- package/dist/{chunk-XRFOYWYI.js → chunk-D6WPLX6I.js} +2 -2
- package/dist/{chunk-EFL5CN6M.js → chunk-DDSNKVSE.js} +4 -4
- package/dist/{chunk-63QEL3SZ.js → chunk-EE47RXD7.js} +4 -4
- package/dist/{chunk-RW6YXHBL.js → chunk-FAJJWN6E.js} +12 -12
- package/dist/{chunk-OOAZSPYS.js → chunk-IH7T5JPW.js} +3 -3
- package/dist/{chunk-DWXXFI3U.js → chunk-IHBQYIUZ.js} +6 -6
- package/dist/{chunk-WNXHHHLZ.js → chunk-ITNVIYE3.js} +3 -3
- package/dist/{chunk-CMFKWJDJ.js → chunk-IWPRI3XU.js} +3 -3
- package/dist/{chunk-EDVQGTOL.js → chunk-K7AOF3FH.js} +4 -4
- package/dist/{chunk-2Q7SKRRM.js → chunk-K7RRB5XV.js} +162 -131
- package/dist/{chunk-3W2QB2OC.js → chunk-KKVOR377.js} +2 -2
- package/dist/{chunk-LY6UIYOG.js → chunk-KNQWUKO7.js} +2 -2
- package/dist/{chunk-ZOTASNQ2.js → chunk-MOWOUC6B.js} +1 -1
- package/dist/{chunk-ONJCU4C5.js → chunk-MUSUHPY2.js} +2 -2
- package/dist/{chunk-O53XNGJU.js → chunk-MVPEKELJ.js} +1 -1
- package/dist/{chunk-YZIPQNOG.js → chunk-MZ2TTN37.js} +2 -2
- package/dist/{chunk-2AH5EBXL.js → chunk-NNUPTNLQ.js} +4 -4
- package/dist/{chunk-UJQBYPRO.js → chunk-OC4AY5G7.js} +1 -1
- package/dist/{chunk-V67RXPI6.js → chunk-PMW2LD65.js} +3 -3
- package/dist/{chunk-5NBS5LAW.js → chunk-Q5FUGUDS.js} +1 -1
- package/dist/{chunk-TXDYKQZT.js → chunk-QMWGTSUE.js} +4 -4
- package/dist/{chunk-JZ5DN7RX.js → chunk-WLP3ZOM3.js} +2509 -728
- package/dist/{chunk-IIVL4DYB.js → chunk-WVPWWPI5.js} +2 -2
- package/dist/{chunk-XDCNK2SU.js → chunk-WZTRJKOI.js} +2 -2
- package/dist/{chunk-B4KDQK3X.js → chunk-XMZ6YUCX.js} +2 -2
- package/dist/{chunk-LUGC3D2G.js → chunk-YWPV7MV2.js} +6 -6
- package/dist/{chunk-HJ2JCW7E.js → chunk-Z5LDVTOK.js} +2 -2
- package/dist/cli/commands/auth/logout.js +18 -18
- package/dist/cli/commands/auth/logout.test.js +19 -19
- package/dist/cli/commands/debug/command-flags.js +17 -17
- package/dist/cli/commands/demo/catalog.js +18 -18
- package/dist/cli/commands/demo/generate-file.js +18 -18
- package/dist/cli/commands/demo/index.js +17 -17
- package/dist/cli/commands/demo/print-ai-prompt.js +18 -18
- package/dist/cli/commands/docs/generate.js +17 -17
- package/dist/cli/commands/docs/generate.test.js +17 -17
- package/dist/cli/commands/help.js +17 -17
- package/dist/cli/commands/kitchen-sink/async.js +18 -18
- package/dist/cli/commands/kitchen-sink/async.test.js +18 -18
- package/dist/cli/commands/kitchen-sink/index.js +20 -20
- package/dist/cli/commands/kitchen-sink/index.test.js +20 -20
- package/dist/cli/commands/kitchen-sink/prompts.js +18 -18
- package/dist/cli/commands/kitchen-sink/prompts.test.js +18 -18
- package/dist/cli/commands/kitchen-sink/static.js +18 -18
- package/dist/cli/commands/kitchen-sink/static.test.js +18 -18
- package/dist/cli/commands/search.js +18 -18
- package/dist/cli/commands/upgrade.js +17 -17
- package/dist/cli/commands/version.js +18 -18
- package/dist/cli/commands/version.test.js +18 -18
- package/dist/cli/services/commands/search.js +8 -8
- package/dist/cli/services/commands/search.test.js +8 -8
- package/dist/cli/services/commands/version.js +11 -11
- package/dist/cli/services/commands/version.test.js +12 -12
- package/dist/cli/services/demo.js +8 -8
- package/dist/cli/services/demo.test.js +8 -8
- package/dist/cli/services/kitchen-sink/async.js +8 -8
- package/dist/cli/services/kitchen-sink/prompts.js +8 -8
- package/dist/cli/services/kitchen-sink/static.js +8 -8
- package/dist/cli/services/upgrade.js +10 -10
- package/dist/cli/services/upgrade.test.js +11 -11
- package/dist/{chunk-5R5656YY.js → custom-oclif-loader-FPNRMQLJ.js} +18 -3
- package/dist/{custom-oclif-loader-KLTAWG4B-VOMMA3PO.js → custom-oclif-loader-RLNBRURI-YQ7IWI5Q.js} +4 -4
- package/dist/{error-handler-UJK7WNJE.js → error-handler-5ZOJ546L.js} +10 -10
- package/dist/{error-handler-ND7WBMC3-CRFJKAS4.js → error-handler-764JJPWK-SOMSJP6S.js} +6 -6
- package/dist/{error-handler-FUQWOW4J.js → error-handler-EOKEDDHC.js} +15 -15
- package/dist/hooks/postrun.js +13 -13
- package/dist/hooks/prerun.js +10 -10
- package/dist/index.js +309 -241
- package/dist/{lib-76RCE6WZ-AR3SQY6Y.js → lib-76RCE6WZ-5IYGTKKK.js} +2 -2
- package/dist/{lib-MWSNLG5P.js → lib-UYK3ZLZK.js} +3 -3
- package/dist/{local-3LWDOA7J-UFWE2V6L.js → local-GRWHBAAP-GLATK6HY.js} +4 -4
- package/dist/{local-5OND5PI5.js → local-S7EXCS5E.js} +7 -7
- package/dist/{morph-FQNWYET7.js → morph-XX23WEJZ.js} +25 -8
- package/dist/{node-WNJUHXTR.js → node-SSGKCHRY.js} +14 -14
- package/dist/{node-package-manager-ISP2P5R3.js → node-package-manager-V7QQWFES.js} +9 -9
- package/dist/{node-package-manager-TFY2ROCP-DDJAU44T.js → node-package-manager-VZCY35QS-AGCABGK7.js} +5 -5
- package/dist/{system-G445DF53.js → system-P6PSEW7S.js} +7 -7
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{ui-ITQVVPJU.js → ui-JSBDAFMV.js} +7 -7
- package/dist/{ui-MUGCNPLG-UG4N3GMV.js → ui-P6NP425V-CKQLZD3E.js} +4 -4
- package/dist/{workerd-EZVOCUQW.js → workerd-3U2NNCIK.js} +13 -13
- package/oclif.manifest.json +1 -1
- package/package.json +4 -5
- package/dist/custom-oclif-loader-PJJ3H2WB.js +0 -28
- package/dist/hooks/init.d.ts +0 -12
- package/dist/hooks/init.js +0 -66
- package/dist/hooks/init.js.map +0 -1
- package/dist/{chunk-67MDUPX5.js → chunk-I434ZJQI.js} +7 -7
- package/dist/{chunk-74JT4RJX.js → chunk-VF4VWJWS.js} +3 -3
|
@@ -1,91 +1,29 @@
|
|
|
1
1
|
# skeleton
|
|
2
2
|
|
|
3
|
-
## 0.0.0-next-
|
|
3
|
+
## 0.0.0-next-a8b9c6c-20240606114114
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
- Refactor root to use [Remix's Layout Export pattern](https://remix.run/docs/en/main/file-conventions/root#layout-export). ([#2152](https://github.com/Shopify/hydrogen/pull/2152)) by [@michenly](https://github.com/michenly)
|
|
10
|
-
|
|
11
|
-
This will also fix below error ahead of Single Fetch future flag.
|
|
12
|
-
|
|
13
|
-
> You cannot `useLoaderData` in an errorElement
|
|
14
|
-
|
|
15
|
-
The diff below showcase how you can make this refactor in your existing application.
|
|
16
|
-
|
|
17
|
-
```diff
|
|
18
|
-
import {
|
|
19
|
-
Outlet,
|
|
20
|
-
- useLoaderData,
|
|
21
|
-
+ useRouteLoaderData,
|
|
22
|
-
} from '@remix-run/react';
|
|
23
|
-
-import {Layout} from '~/components/Layout';
|
|
24
|
-
+import {PageLayout} from '~/components/PageLayout';
|
|
25
|
-
|
|
26
|
-
-export default function App() {
|
|
27
|
-
+export function Layout({children}: {children?: React.ReactNode}) {
|
|
28
|
-
const nonce = useNonce();
|
|
29
|
-
- const data = useLoaderData<typeof loader>();
|
|
30
|
-
+ const data = useRouteLoaderData<typeof loader>('root');
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<html>
|
|
34
|
-
...
|
|
35
|
-
<body>
|
|
36
|
-
- <Layout {...data}>
|
|
37
|
-
- <Outlet />
|
|
38
|
-
- </Layout>
|
|
39
|
-
+ {data? (
|
|
40
|
-
+ <PageLayout {...data}>
|
|
41
|
-
+ {children}
|
|
42
|
-
+ </PageLayout>
|
|
43
|
-
+ ) : (
|
|
44
|
-
+ children
|
|
45
|
-
+ )}
|
|
46
|
-
</body>
|
|
47
|
-
</html>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
7
|
+
- Trigger changeset for all packages for next release
|
|
50
8
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
9
|
+
- Updated dependencies []:
|
|
10
|
+
- @shopify/hydrogen@0.0.0-next-a8b9c6c-20240606114114
|
|
11
|
+
- @shopify/cli-hydrogen@0.0.0-next-a8b9c6c-20240606114114
|
|
12
|
+
- @shopify/remix-oxygen@0.0.0-next-a8b9c6c-20240606114114
|
|
54
13
|
|
|
55
|
-
|
|
56
|
-
const rootData = useLoaderData<typeof loader>();
|
|
14
|
+
## 2024.4.5
|
|
57
15
|
|
|
58
|
-
|
|
59
|
-
- <html>
|
|
60
|
-
- ...
|
|
61
|
-
- <body>
|
|
62
|
-
- <Layout {...rootData}>
|
|
63
|
-
- <div className="route-error">
|
|
64
|
-
- <h1>Error</h1>
|
|
65
|
-
- ...
|
|
66
|
-
- </div>
|
|
67
|
-
- </Layout>
|
|
68
|
-
- </body>
|
|
69
|
-
- </html>
|
|
70
|
-
+ <div className="route-error">
|
|
71
|
-
+ <h1>Error</h1>
|
|
72
|
-
+ ...
|
|
73
|
-
+ </div>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
16
|
+
### Patch Changes
|
|
76
17
|
|
|
77
|
-
|
|
18
|
+
- Update remix to v2.9.2 ([#2135](https://github.com/Shopify/hydrogen/pull/2135)) by [@michenly](https://github.com/michenly)
|
|
78
19
|
|
|
79
20
|
- `<Analytics>` and `useAnalytics` are now stable. ([#2141](https://github.com/Shopify/hydrogen/pull/2141)) by [@wizardlyhel](https://github.com/wizardlyhel)
|
|
80
21
|
|
|
81
|
-
- Trigger changeset for all packages for next release
|
|
82
|
-
|
|
83
22
|
- Update the skeleton template to use React state in the aside dialogs ([#2088](https://github.com/Shopify/hydrogen/pull/2088)) by [@blittle](https://github.com/blittle)
|
|
84
23
|
|
|
85
|
-
- Updated dependencies [[`fe82119f`](https://github.com/Shopify/hydrogen/commit/fe82119f5e75df5a0f727bab6a2186e679abc73d), [`32d4c33e`](https://github.com/Shopify/hydrogen/commit/32d4c33e4421a9c56f62a8c392f5417edddd0402), [`8eea75ec`](https://github.com/Shopify/hydrogen/commit/8eea75ec5ead4de98d7d1b2baedce8511029bcae), [`27e51abf`](https://github.com/Shopify/hydrogen/commit/27e51abfc1f5444afa952c503886bfa12fc55c7e), [`f29c9085`](https://github.com/Shopify/hydrogen/commit/f29c9085eb1adbde9e01226484eba8a85b5074ed), [`7b838beb`](https://github.com/Shopify/hydrogen/commit/7b838beb7c43380ffc9c32c2bb9f34291912fa42), [`
|
|
86
|
-
- @shopify/hydrogen@
|
|
87
|
-
- @shopify/cli-hydrogen@
|
|
88
|
-
- @shopify/remix-oxygen@0.0.0-next-ca7f288-20240530103543
|
|
24
|
+
- Updated dependencies [[`fe82119f`](https://github.com/Shopify/hydrogen/commit/fe82119f5e75df5a0f727bab6a2186e679abc73d), [`32d4c33e`](https://github.com/Shopify/hydrogen/commit/32d4c33e4421a9c56f62a8c392f5417edddd0402), [`8eea75ec`](https://github.com/Shopify/hydrogen/commit/8eea75ec5ead4de98d7d1b2baedce8511029bcae), [`27e51abf`](https://github.com/Shopify/hydrogen/commit/27e51abfc1f5444afa952c503886bfa12fc55c7e), [`f29c9085`](https://github.com/Shopify/hydrogen/commit/f29c9085eb1adbde9e01226484eba8a85b5074ed), [`7b838beb`](https://github.com/Shopify/hydrogen/commit/7b838beb7c43380ffc9c32c2bb9f34291912fa42), [`d702aec2`](https://github.com/Shopify/hydrogen/commit/d702aec2214646a78cdafc2c25d510489db73f6d), [`ca4cf045`](https://github.com/Shopify/hydrogen/commit/ca4cf045f7fb72ad98b62af7bd172ff8cf553de2), [`5a554b2e`](https://github.com/Shopify/hydrogen/commit/5a554b2e9d91894c2db8032f0c29666dce1ea3f2), [`27e51abf`](https://github.com/Shopify/hydrogen/commit/27e51abfc1f5444afa952c503886bfa12fc55c7e), [`5d6465b3`](https://github.com/Shopify/hydrogen/commit/5d6465b32d90052e5580fcb81d98427bcb8ad528), [`608389d6`](https://github.com/Shopify/hydrogen/commit/608389d6d69c6a9801935d528507c165d1dd4ccf), [`9dfd1cfe`](https://github.com/Shopify/hydrogen/commit/9dfd1cfeb3e96c6d3426427a4b5d97ef475dab6d), [`7def3e9f`](https://github.com/Shopify/hydrogen/commit/7def3e9fa6e28f4fde7af43e2f346aa32267c38e), [`65239c76`](https://github.com/Shopify/hydrogen/commit/65239c76ca1d0b294b59b1ad53624485859c4da5), [`ca7f2888`](https://github.com/Shopify/hydrogen/commit/ca7f28887367a4882e57a67c4e248b0f0bba1c9b)]:
|
|
25
|
+
- @shopify/hydrogen@2024.4.3
|
|
26
|
+
- @shopify/cli-hydrogen@8.1.0
|
|
89
27
|
|
|
90
28
|
## 2024.4.4
|
|
91
29
|
|
|
@@ -3,7 +3,7 @@ import {Await, NavLink} from '@remix-run/react';
|
|
|
3
3
|
import type {FooterQuery, HeaderQuery} from 'storefrontapi.generated';
|
|
4
4
|
|
|
5
5
|
interface FooterProps {
|
|
6
|
-
footer: Promise<FooterQuery>;
|
|
6
|
+
footer: Promise<FooterQuery | null>;
|
|
7
7
|
header: HeaderQuery;
|
|
8
8
|
publicStoreDomain: string;
|
|
9
9
|
}
|
|
@@ -18,7 +18,7 @@ export function Footer({
|
|
|
18
18
|
<Await resolve={footerPromise}>
|
|
19
19
|
{(footer) => (
|
|
20
20
|
<footer className="footer">
|
|
21
|
-
{footer
|
|
21
|
+
{footer?.menu && header.shop.primaryDomain?.url && (
|
|
22
22
|
<FooterMenu
|
|
23
23
|
menu={footer.menu}
|
|
24
24
|
primaryDomainUrl={header.shop.primaryDomain.url}
|
|
@@ -37,7 +37,7 @@ function FooterMenu({
|
|
|
37
37
|
primaryDomainUrl,
|
|
38
38
|
publicStoreDomain,
|
|
39
39
|
}: {
|
|
40
|
-
menu:
|
|
40
|
+
menu: FooterQuery['menu'];
|
|
41
41
|
primaryDomainUrl: FooterProps['header']['shop']['primaryDomain']['url'];
|
|
42
42
|
publicStoreDomain: string;
|
|
43
43
|
}) {
|
|
@@ -56,36 +56,20 @@ export function links() {
|
|
|
56
56
|
];
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export async function loader(
|
|
60
|
-
|
|
61
|
-
const
|
|
59
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
60
|
+
// Start fetching non-critical data without blocking time to first byte
|
|
61
|
+
const deferredData = loadDeferredData(args);
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
const
|
|
63
|
+
// Await the critical data required to render initial state of the page
|
|
64
|
+
const criticalData = await loadCriticalData(args);
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
const footerPromise = storefront.query(FOOTER_QUERY, {
|
|
68
|
-
cache: storefront.CacheLong(),
|
|
69
|
-
variables: {
|
|
70
|
-
footerMenuHandle: 'footer', // Adjust to your footer menu handle
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// await the header query (above the fold)
|
|
75
|
-
const headerPromise = storefront.query(HEADER_QUERY, {
|
|
76
|
-
cache: storefront.CacheLong(),
|
|
77
|
-
variables: {
|
|
78
|
-
headerMenuHandle: 'main-menu', // Adjust to your header menu handle
|
|
79
|
-
},
|
|
80
|
-
});
|
|
66
|
+
const {storefront, env} = args.context;
|
|
81
67
|
|
|
82
68
|
return defer(
|
|
83
69
|
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
isLoggedIn: isLoggedInPromise,
|
|
88
|
-
publicStoreDomain,
|
|
70
|
+
...deferredData,
|
|
71
|
+
...criticalData,
|
|
72
|
+
publicStoreDomain: env.PUBLIC_STORE_DOMAIN,
|
|
89
73
|
shop: getShopAnalytics({
|
|
90
74
|
storefront,
|
|
91
75
|
publicStorefrontId: env.PUBLIC_STOREFRONT_ID,
|
|
@@ -97,13 +81,63 @@ export async function loader({context}: LoaderFunctionArgs) {
|
|
|
97
81
|
},
|
|
98
82
|
{
|
|
99
83
|
headers: {
|
|
100
|
-
'Set-Cookie': await context.session.commit(),
|
|
84
|
+
'Set-Cookie': await args.context.session.commit(),
|
|
101
85
|
},
|
|
102
86
|
},
|
|
103
87
|
);
|
|
104
88
|
}
|
|
105
89
|
|
|
106
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Load data necessary for rendering content above the fold. This is the critical data
|
|
92
|
+
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
93
|
+
*/
|
|
94
|
+
async function loadCriticalData({context}: LoaderFunctionArgs) {
|
|
95
|
+
const {storefront} = context;
|
|
96
|
+
|
|
97
|
+
const [header] = await Promise.all([
|
|
98
|
+
storefront.query(HEADER_QUERY, {
|
|
99
|
+
cache: storefront.CacheLong(),
|
|
100
|
+
variables: {
|
|
101
|
+
headerMenuHandle: 'main-menu', // Adjust to your header menu handle
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
// Add other queries here, so that they are loaded in parallel
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
header,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Load data for rendering content below the fold. This data is deferred and will be
|
|
114
|
+
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
115
|
+
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
116
|
+
*/
|
|
117
|
+
function loadDeferredData({context}: LoaderFunctionArgs) {
|
|
118
|
+
const {storefront, customerAccount, cart} = context;
|
|
119
|
+
|
|
120
|
+
// defer the footer query (below the fold)
|
|
121
|
+
const footer = storefront
|
|
122
|
+
.query(FOOTER_QUERY, {
|
|
123
|
+
cache: storefront.CacheLong(),
|
|
124
|
+
variables: {
|
|
125
|
+
footerMenuHandle: 'footer', // Adjust to your footer menu handle
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
.catch((error) => {
|
|
129
|
+
// Log query errors, but don't throw them so the page can still render
|
|
130
|
+
console.error(error);
|
|
131
|
+
return null;
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
cart: cart.get(),
|
|
135
|
+
isLoggedIn: customerAccount.isLoggedIn(),
|
|
136
|
+
footer,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function Layout({children}: {children?: React.ReactNode}) {
|
|
107
141
|
const nonce = useNonce();
|
|
108
142
|
const data = useRouteLoaderData<RootLoader>('root');
|
|
109
143
|
|
|
@@ -135,7 +169,11 @@ export function Layout({children}: {children?: React.ReactNode}) {
|
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
export default function App() {
|
|
138
|
-
return
|
|
172
|
+
return (
|
|
173
|
+
<Layout>
|
|
174
|
+
<Outlet />
|
|
175
|
+
</Layout>
|
|
176
|
+
);
|
|
139
177
|
}
|
|
140
178
|
|
|
141
179
|
export function ErrorBoundary() {
|
|
@@ -151,14 +189,16 @@ export function ErrorBoundary() {
|
|
|
151
189
|
}
|
|
152
190
|
|
|
153
191
|
return (
|
|
154
|
-
<
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
192
|
+
<Layout>
|
|
193
|
+
<div className="route-error">
|
|
194
|
+
<h1>Oops</h1>
|
|
195
|
+
<h2>{errorStatus}</h2>
|
|
196
|
+
{errorMessage && (
|
|
197
|
+
<fieldset>
|
|
198
|
+
<pre>{errorMessage}</pre>
|
|
199
|
+
</fieldset>
|
|
200
|
+
)}
|
|
201
|
+
</div>
|
|
202
|
+
</Layout>
|
|
163
203
|
);
|
|
164
204
|
}
|
|
@@ -11,13 +11,48 @@ export const meta: MetaFunction = () => {
|
|
|
11
11
|
return [{title: 'Hydrogen | Home'}];
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export async function loader(
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const featuredCollection = collections.nodes[0];
|
|
18
|
-
const recommendedProducts = storefront.query(RECOMMENDED_PRODUCTS_QUERY);
|
|
14
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
15
|
+
// Start fetching non-critical data without blocking time to first byte
|
|
16
|
+
const deferredData = loadDeferredData(args);
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
// Await the critical data required to render initial state of the page
|
|
19
|
+
const criticalData = await loadCriticalData(args);
|
|
20
|
+
|
|
21
|
+
return defer({...deferredData, ...criticalData});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Load data necessary for rendering content above the fold. This is the critical data
|
|
26
|
+
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
27
|
+
*/
|
|
28
|
+
async function loadCriticalData({context}: LoaderFunctionArgs) {
|
|
29
|
+
const [{collections}] = await Promise.all([
|
|
30
|
+
context.storefront.query(FEATURED_COLLECTION_QUERY),
|
|
31
|
+
// Add other queries here, so that they are loaded in parallel
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
featuredCollection: collections.nodes[0],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Load data for rendering content below the fold. This data is deferred and will be
|
|
41
|
+
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
42
|
+
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
43
|
+
*/
|
|
44
|
+
function loadDeferredData({context}: LoaderFunctionArgs) {
|
|
45
|
+
const recommendedProducts = context.storefront
|
|
46
|
+
.query(RECOMMENDED_PRODUCTS_QUERY)
|
|
47
|
+
.catch((error) => {
|
|
48
|
+
// Log query errors, but don't throw them so the page can still render
|
|
49
|
+
console.error(error);
|
|
50
|
+
return null;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
recommendedProducts,
|
|
55
|
+
};
|
|
21
56
|
}
|
|
22
57
|
|
|
23
58
|
export default function Homepage() {
|
|
@@ -55,32 +90,34 @@ function FeaturedCollection({
|
|
|
55
90
|
function RecommendedProducts({
|
|
56
91
|
products,
|
|
57
92
|
}: {
|
|
58
|
-
products: Promise<RecommendedProductsQuery>;
|
|
93
|
+
products: Promise<RecommendedProductsQuery | null>;
|
|
59
94
|
}) {
|
|
60
95
|
return (
|
|
61
96
|
<div className="recommended-products">
|
|
62
97
|
<h2>Recommended Products</h2>
|
|
63
98
|
<Suspense fallback={<div>Loading...</div>}>
|
|
64
99
|
<Await resolve={products}>
|
|
65
|
-
{(
|
|
100
|
+
{(response) => (
|
|
66
101
|
<div className="recommended-products-grid">
|
|
67
|
-
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
{response
|
|
103
|
+
? response.products.nodes.map((product) => (
|
|
104
|
+
<Link
|
|
105
|
+
key={product.id}
|
|
106
|
+
className="recommended-product"
|
|
107
|
+
to={`/products/${product.handle}`}
|
|
108
|
+
>
|
|
109
|
+
<Image
|
|
110
|
+
data={product.images.nodes[0]}
|
|
111
|
+
aspectRatio="1/1"
|
|
112
|
+
sizes="(min-width: 45em) 20vw, 50vw"
|
|
113
|
+
/>
|
|
114
|
+
<h4>{product.title}</h4>
|
|
115
|
+
<small>
|
|
116
|
+
<Money data={product.priceRange.minVariantPrice} />
|
|
117
|
+
</small>
|
|
118
|
+
</Link>
|
|
119
|
+
))
|
|
120
|
+
: null}
|
|
84
121
|
</div>
|
|
85
122
|
)}
|
|
86
123
|
</Await>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {defer, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
2
2
|
import {useLoaderData, type MetaFunction} from '@remix-run/react';
|
|
3
3
|
import {Image} from '@shopify/hydrogen';
|
|
4
4
|
|
|
@@ -6,16 +6,33 @@ export const meta: MetaFunction<typeof loader> = ({data}) => {
|
|
|
6
6
|
return [{title: `Hydrogen | ${data?.article.title ?? ''} article`}];
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export async function loader(
|
|
9
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
10
|
+
// Start fetching non-critical data without blocking time to first byte
|
|
11
|
+
const deferredData = loadDeferredData(args);
|
|
12
|
+
|
|
13
|
+
// Await the critical data required to render initial state of the page
|
|
14
|
+
const criticalData = await loadCriticalData(args);
|
|
15
|
+
|
|
16
|
+
return defer({...deferredData, ...criticalData});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Load data necessary for rendering content above the fold. This is the critical data
|
|
21
|
+
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
22
|
+
*/
|
|
23
|
+
async function loadCriticalData({context, params}: LoaderFunctionArgs) {
|
|
10
24
|
const {blogHandle, articleHandle} = params;
|
|
11
25
|
|
|
12
26
|
if (!articleHandle || !blogHandle) {
|
|
13
27
|
throw new Response('Not found', {status: 404});
|
|
14
28
|
}
|
|
15
29
|
|
|
16
|
-
const {blog} = await
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
const [{blog}] = await Promise.all([
|
|
31
|
+
context.storefront.query(ARTICLE_QUERY, {
|
|
32
|
+
variables: {blogHandle, articleHandle},
|
|
33
|
+
}),
|
|
34
|
+
// Add other queries here, so that they are loaded in parallel
|
|
35
|
+
]);
|
|
19
36
|
|
|
20
37
|
if (!blog?.articleByHandle) {
|
|
21
38
|
throw new Response(null, {status: 404});
|
|
@@ -23,7 +40,16 @@ export async function loader({params, context}: LoaderFunctionArgs) {
|
|
|
23
40
|
|
|
24
41
|
const article = blog.articleByHandle;
|
|
25
42
|
|
|
26
|
-
return
|
|
43
|
+
return {article};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Load data for rendering content below the fold. This data is deferred and will be
|
|
48
|
+
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
49
|
+
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
50
|
+
*/
|
|
51
|
+
function loadDeferredData({context}: LoaderFunctionArgs) {
|
|
52
|
+
return {};
|
|
27
53
|
}
|
|
28
54
|
|
|
29
55
|
export default function Article() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {defer, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
2
2
|
import {Link, useLoaderData, type MetaFunction} from '@remix-run/react';
|
|
3
3
|
import {Image, Pagination, getPaginationVariables} from '@shopify/hydrogen';
|
|
4
4
|
import type {ArticleItemFragment} from 'storefrontapi.generated';
|
|
@@ -7,10 +7,24 @@ export const meta: MetaFunction<typeof loader> = ({data}) => {
|
|
|
7
7
|
return [{title: `Hydrogen | ${data?.blog.title ?? ''} blog`}];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export async function loader({
|
|
10
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
11
|
+
// Start fetching non-critical data without blocking time to first byte
|
|
12
|
+
const deferredData = loadDeferredData(args);
|
|
13
|
+
|
|
14
|
+
// Await the critical data required to render initial state of the page
|
|
15
|
+
const criticalData = await loadCriticalData(args);
|
|
16
|
+
|
|
17
|
+
return defer({...deferredData, ...criticalData});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load data necessary for rendering content above the fold. This is the critical data
|
|
22
|
+
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
23
|
+
*/
|
|
24
|
+
async function loadCriticalData({
|
|
25
|
+
context,
|
|
11
26
|
request,
|
|
12
27
|
params,
|
|
13
|
-
context: {storefront},
|
|
14
28
|
}: LoaderFunctionArgs) {
|
|
15
29
|
const paginationVariables = getPaginationVariables(request, {
|
|
16
30
|
pageBy: 4,
|
|
@@ -20,18 +34,30 @@ export async function loader({
|
|
|
20
34
|
throw new Response(`blog not found`, {status: 404});
|
|
21
35
|
}
|
|
22
36
|
|
|
23
|
-
const {blog} = await
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
const [{blog}] = await Promise.all([
|
|
38
|
+
context.storefront.query(BLOGS_QUERY, {
|
|
39
|
+
variables: {
|
|
40
|
+
blogHandle: params.blogHandle,
|
|
41
|
+
...paginationVariables,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
// Add other queries here, so that they are loaded in parallel
|
|
45
|
+
]);
|
|
29
46
|
|
|
30
47
|
if (!blog?.articles) {
|
|
31
48
|
throw new Response('Not found', {status: 404});
|
|
32
49
|
}
|
|
33
50
|
|
|
34
|
-
return
|
|
51
|
+
return {blog};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load data for rendering content below the fold. This data is deferred and will be
|
|
56
|
+
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
57
|
+
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
58
|
+
*/
|
|
59
|
+
function loadDeferredData({context}: LoaderFunctionArgs) {
|
|
60
|
+
return {};
|
|
35
61
|
}
|
|
36
62
|
|
|
37
63
|
export default function Blog() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {defer, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
2
2
|
import {Link, useLoaderData, type MetaFunction} from '@remix-run/react';
|
|
3
3
|
import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
|
|
4
4
|
|
|
@@ -6,22 +6,45 @@ export const meta: MetaFunction = () => {
|
|
|
6
6
|
return [{title: `Hydrogen | Blogs`}];
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
10
|
+
// Start fetching non-critical data without blocking time to first byte
|
|
11
|
+
const deferredData = loadDeferredData(args);
|
|
12
|
+
|
|
13
|
+
// Await the critical data required to render initial state of the page
|
|
14
|
+
const criticalData = await loadCriticalData(args);
|
|
15
|
+
|
|
16
|
+
return defer({...deferredData, ...criticalData});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Load data necessary for rendering content above the fold. This is the critical data
|
|
21
|
+
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
22
|
+
*/
|
|
23
|
+
async function loadCriticalData({context, request}: LoaderFunctionArgs) {
|
|
13
24
|
const paginationVariables = getPaginationVariables(request, {
|
|
14
25
|
pageBy: 10,
|
|
15
26
|
});
|
|
16
27
|
|
|
17
|
-
const {blogs} = await
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
const [{blogs}] = await Promise.all([
|
|
29
|
+
context.storefront.query(BLOGS_QUERY, {
|
|
30
|
+
variables: {
|
|
31
|
+
...paginationVariables,
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
// Add other queries here, so that they are loaded in parallel
|
|
35
|
+
]);
|
|
22
36
|
|
|
23
|
-
return
|
|
24
|
-
}
|
|
37
|
+
return {blogs};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Load data for rendering content below the fold. This data is deferred and will be
|
|
42
|
+
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
43
|
+
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
44
|
+
*/
|
|
45
|
+
function loadDeferredData({context}: LoaderFunctionArgs) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
25
48
|
|
|
26
49
|
export default function Blogs() {
|
|
27
50
|
const {blogs} = useLoaderData<typeof loader>();
|