@shopify/hydrogen 0.12.0 → 0.13.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/CHANGELOG.md +331 -27
- package/dist/esnext/client.d.ts +2 -0
- package/dist/esnext/client.js +2 -0
- package/dist/esnext/components/CartLineProvider/context.d.ts +10 -10
- package/dist/esnext/components/CartProvider/CartProvider.client.d.ts +1 -1
- package/dist/esnext/components/CartProvider/CartProvider.client.js +2 -1
- package/dist/esnext/components/CartProvider/cart-queries.d.ts +9 -0
- package/dist/esnext/components/CartProvider/cart-queries.js +876 -0
- package/dist/esnext/components/CartProvider/graphql/CartAttributesUpdateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartBuyerIdentityUpdateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartCreateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartDiscountCodesUpdateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartFragment.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartLineAddMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartLineRemoveMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartLineUpdateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartNoteUpdateMutation.d.ts +1 -1
- package/dist/esnext/components/CartProvider/graphql/CartQuery.d.ts +1 -1
- package/dist/esnext/components/CartProvider/hooks.d.ts +1 -1
- package/dist/esnext/components/CartProvider/hooks.js +4 -1
- package/dist/esnext/components/CartProvider/types.d.ts +1 -1
- package/dist/esnext/components/ExternalVideo/ExternalVideo.d.ts +6 -5
- package/dist/esnext/components/ExternalVideo/ExternalVideo.js +5 -2
- package/dist/esnext/components/Image/Image.d.ts +14 -12
- package/dist/esnext/components/Image/Image.js +17 -14
- package/dist/esnext/components/Link/Link.client.d.ts +4 -5
- package/dist/esnext/components/Link/Link.client.js +5 -4
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +1 -3
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +2 -2
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +15 -4
- package/dist/esnext/components/LocalizationProvider/LocalizationQuery.d.ts +1 -8
- package/dist/esnext/components/LocalizationProvider/index.d.ts +0 -1
- package/dist/esnext/components/LocalizationProvider/index.js +0 -1
- package/dist/esnext/components/MediaFile/MediaFile.d.ts +4 -3
- package/dist/esnext/components/Metafield/Metafield.client.d.ts +2 -2
- package/dist/esnext/components/Metafield/Metafield.client.js +8 -5
- package/dist/esnext/components/Metafield/types.d.ts +1 -1
- package/dist/esnext/components/ModelViewer/ModelViewer.client.d.ts +57 -56
- package/dist/esnext/components/ModelViewer/ModelViewer.client.js +10 -4
- package/dist/esnext/components/Money/Money.client.d.ts +5 -4
- package/dist/esnext/components/Money/Money.client.js +1 -1
- package/dist/esnext/components/ProductDescription/ProductDescription.client.d.ts +9 -4
- package/dist/esnext/components/ProductDescription/ProductDescription.client.js +4 -3
- package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +3 -3
- package/dist/esnext/components/ProductPrice/ProductPrice.client.js +2 -2
- package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +3 -2
- package/dist/esnext/components/ProductProvider/ProductProvider.client.js +1 -0
- package/dist/esnext/components/ProductProvider/context.d.ts +23 -14
- package/dist/esnext/components/Seo/CollectionSeo.client.d.ts +3 -2
- package/dist/esnext/components/Seo/CollectionSeo.client.js +2 -2
- package/dist/esnext/components/Seo/DefaultPageSeo.client.d.ts +3 -2
- package/dist/esnext/components/Seo/DescriptionSeo.client.d.ts +2 -2
- package/dist/esnext/components/Seo/HomePageSeo.client.d.ts +1 -1
- package/dist/esnext/components/Seo/ImageSeo.client.d.ts +3 -2
- package/dist/esnext/components/Seo/ImageSeo.client.js +1 -1
- package/dist/esnext/components/Seo/PageSeo.client.d.ts +3 -2
- package/dist/esnext/components/Seo/ProductSeo.client.d.ts +3 -3
- package/dist/esnext/components/Seo/ProductSeo.client.js +10 -5
- package/dist/esnext/components/Seo/Seo.client.d.ts +10 -7
- package/dist/esnext/components/Seo/TitleSeo.client.d.ts +3 -4
- package/dist/esnext/components/Seo/TwitterSeo.client.d.ts +1 -1
- package/dist/esnext/components/Seo/seo-types.d.ts +17 -0
- package/dist/esnext/components/{ExternalVideo/ExternalVideoFragment.js → Seo/seo-types.js} +0 -0
- package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +7 -6
- package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -1
- package/dist/esnext/components/Video/Video.d.ts +5 -4
- package/dist/esnext/components/Video/Video.js +10 -2
- package/dist/esnext/components/index.d.ts +0 -3
- package/dist/esnext/components/index.js +0 -3
- package/dist/esnext/entry-client.js +9 -4
- package/dist/esnext/entry-server.d.ts +1 -0
- package/dist/esnext/entry-server.js +101 -88
- package/dist/esnext/foundation/FileRoutes/FileRoutes.server.d.ts +22 -0
- package/dist/esnext/foundation/{Router/FileRoutes.js → FileRoutes/FileRoutes.server.js} +20 -10
- package/dist/esnext/foundation/Redirect/Redirect.client.d.ts +5 -0
- package/dist/esnext/foundation/Redirect/Redirect.client.js +14 -0
- package/dist/esnext/foundation/Route/Route.server.d.ts +12 -0
- package/dist/esnext/foundation/Route/Route.server.js +33 -0
- package/dist/esnext/foundation/Router/{Router.d.ts → BrowserRouter.client.d.ts} +3 -2
- package/dist/esnext/foundation/Router/{Router.js → BrowserRouter.client.js} +7 -5
- package/dist/esnext/foundation/Router/Router.server.d.ts +5 -3
- package/dist/esnext/foundation/Router/Router.server.js +7 -22
- package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +19 -24
- package/dist/esnext/foundation/ShopifyProvider/index.d.ts +0 -1
- package/dist/esnext/foundation/ShopifyProvider/index.js +0 -1
- package/dist/esnext/foundation/index.d.ts +0 -1
- package/dist/esnext/foundation/index.js +0 -1
- package/dist/esnext/{hooks → foundation}/useNavigate/useNavigate.d.ts +6 -3
- package/dist/esnext/{hooks → foundation}/useNavigate/useNavigate.js +4 -1
- package/dist/esnext/foundation/useQuery/hooks.d.ts +5 -4
- package/dist/esnext/foundation/useQuery/hooks.js +13 -4
- package/dist/esnext/foundation/useRouteParams/RouteParamsProvider.client.d.ts +9 -0
- package/dist/esnext/foundation/useRouteParams/RouteParamsProvider.client.js +7 -0
- package/dist/esnext/foundation/useRouteParams/useRouteParams.d.ts +4 -0
- package/dist/esnext/foundation/useRouteParams/useRouteParams.js +9 -0
- package/dist/esnext/foundation/useUrl/useUrl.js +1 -1
- package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +13 -0
- package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +28 -7
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +4 -1
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +5 -0
- package/dist/esnext/framework/cache/in-memory.d.ts +1 -0
- package/dist/esnext/framework/cache/in-memory.js +15 -5
- package/dist/esnext/framework/middleware.js +25 -3
- package/dist/esnext/framework/plugin.js +6 -1
- package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.d.ts +2 -0
- package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +28 -0
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +61 -75
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/esnext/hooks/index.d.ts +0 -1
- package/dist/esnext/hooks/index.js +0 -1
- package/dist/esnext/hooks/useCartLine/useCartLine.d.ts +10 -10
- package/dist/esnext/hooks/useCountry/useCountry.d.ts +4 -4
- package/dist/esnext/hooks/useMoney/hooks.d.ts +3 -3
- package/dist/esnext/hooks/useMoney/hooks.js +2 -2
- package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.d.ts +17 -2
- package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.js +7 -3
- package/dist/esnext/hooks/useProduct/useProduct.d.ts +34 -96
- package/dist/esnext/hooks/useProductOptions/helpers.d.ts +6 -4
- package/dist/esnext/hooks/useProductOptions/helpers.js +13 -6
- package/dist/esnext/hooks/useProductOptions/types.d.ts +15 -35
- package/dist/esnext/hooks/useProductOptions/useProductOptions.d.ts +6 -5
- package/dist/esnext/hooks/useProductOptions/useProductOptions.js +13 -3
- package/dist/esnext/hooks/useShopQuery/hooks.js +68 -15
- package/dist/esnext/index.d.ts +7 -5
- package/dist/esnext/index.js +7 -5
- package/dist/esnext/platforms/node.d.ts +2 -3
- package/dist/esnext/platforms/node.js +5 -3
- package/dist/esnext/platforms/worker-event.d.ts +0 -8
- package/dist/esnext/platforms/worker-event.js +2 -23
- package/dist/esnext/platforms/worker.d.ts +14 -0
- package/dist/esnext/platforms/worker.js +25 -0
- package/dist/esnext/{graphql/types/types.d.ts → storefront-api-types.d.ts} +389 -32
- package/dist/esnext/{graphql/types/types.js → storefront-api-types.js} +326 -30
- package/dist/esnext/streaming.server.d.ts +9 -5
- package/dist/esnext/streaming.server.js +2 -18
- package/dist/esnext/types.d.ts +1 -16
- package/dist/esnext/utilities/apiRoutes.d.ts +5 -1
- package/dist/esnext/utilities/apiRoutes.js +5 -4
- package/dist/esnext/utilities/devtools.d.ts +11 -0
- package/dist/esnext/utilities/devtools.js +11 -0
- package/dist/esnext/utilities/fetch.d.ts +7 -1
- package/dist/esnext/utilities/fetch.js +9 -10
- package/dist/esnext/utilities/flattenConnection/flattenConnection.d.ts +3 -2
- package/dist/esnext/utilities/flattenConnection/flattenConnection.js +6 -2
- package/dist/esnext/utilities/graphql-tracker.d.ts +17 -0
- package/dist/esnext/utilities/graphql-tracker.js +119 -0
- package/dist/esnext/utilities/image_size.d.ts +5 -4
- package/dist/esnext/utilities/log/log-query-timeline.d.ts +1 -1
- package/dist/esnext/utilities/log/log-query-timeline.js +1 -2
- package/dist/esnext/utilities/log/log.d.ts +1 -0
- package/dist/esnext/utilities/log/utils.js +3 -0
- package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +3 -2
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/entry-server.d.ts +1 -0
- package/dist/node/entry-server.js +106 -89
- package/dist/node/foundation/Redirect/Redirect.client.d.ts +5 -0
- package/dist/node/foundation/Redirect/Redirect.client.js +17 -0
- package/dist/node/foundation/Router/BrowserRouter.client.d.ts +13 -0
- package/dist/node/foundation/Router/BrowserRouter.client.js +77 -0
- package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +24 -25
- package/dist/node/foundation/ServerRequestProvider/index.js +5 -1
- package/dist/node/foundation/ServerStateProvider/ServerStateProvider.js +5 -1
- package/dist/node/foundation/ssr-interop.d.ts +29 -0
- package/dist/node/foundation/ssr-interop.js +39 -0
- package/dist/node/foundation/useNavigate/useNavigate.d.ts +13 -0
- package/dist/node/foundation/useNavigate/useNavigate.js +18 -0
- package/dist/node/foundation/useServerState/index.d.ts +1 -0
- package/dist/node/foundation/useServerState/index.js +5 -0
- package/dist/node/foundation/useServerState/use-server-state.d.ts +16 -0
- package/dist/node/foundation/useServerState/use-server-state.js +24 -0
- package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +13 -0
- package/dist/node/framework/Hydration/ServerComponentRequest.server.js +28 -7
- package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +4 -1
- package/dist/node/framework/Hydration/ServerComponentResponse.server.js +8 -0
- package/dist/node/framework/cache/in-memory.d.ts +1 -0
- package/dist/node/framework/cache/in-memory.js +15 -5
- package/dist/node/framework/middleware.js +30 -4
- package/dist/node/framework/plugin.js +11 -2
- package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.d.ts +2 -0
- package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +31 -0
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +61 -75
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/node/{graphql/types/types.d.ts → storefront-api-types.d.ts} +389 -32
- package/dist/node/{graphql/types/types.js → storefront-api-types.js} +327 -31
- package/dist/node/streaming.server.d.ts +9 -5
- package/dist/node/streaming.server.js +2 -18
- package/dist/node/types.d.ts +1 -16
- package/dist/node/utilities/apiRoutes.d.ts +5 -1
- package/dist/node/utilities/apiRoutes.js +5 -4
- package/dist/node/utilities/fetch.d.ts +7 -1
- package/dist/node/utilities/fetch.js +9 -10
- package/dist/node/utilities/log/log-query-timeline.d.ts +1 -1
- package/dist/node/utilities/log/log-query-timeline.js +1 -2
- package/dist/node/utilities/log/log.d.ts +1 -0
- package/dist/node/utilities/log/utils.js +3 -0
- package/dist/node/utilities/web-api-polyfill.js +5 -1
- package/dist/node/version.d.ts +1 -1
- package/dist/node/version.js +1 -1
- package/package.json +9 -12
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +43 -104
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.development.server.js +1566 -848
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.production.min.server.js +36 -421
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.development.server.js +1523 -864
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.production.min.server.js +35 -437
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.development.js +507 -517
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.production.min.js +10 -246
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +16 -23
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +47 -108
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js +1033 -306
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.node.server.js +965 -293
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite.js +98 -108
- package/vendor/react-server-dom-vite/package.json +0 -2
- package/dist/esnext/components/ExternalVideo/ExternalVideoFragment.d.ts +0 -8
- package/dist/esnext/components/Image/ImageFragment.d.ts +0 -8
- package/dist/esnext/components/Image/ImageFragment.js +0 -1
- package/dist/esnext/components/MediaFile/MediaFileFragment.d.ts +0 -36
- package/dist/esnext/components/MediaFile/MediaFileFragment.js +0 -1
- package/dist/esnext/components/Metafield/MetafieldFragment.d.ts +0 -22
- package/dist/esnext/components/Metafield/MetafieldFragment.js +0 -1
- package/dist/esnext/components/ModelViewer/Model3DFragment.d.ts +0 -15
- package/dist/esnext/components/ModelViewer/Model3DFragment.js +0 -1
- package/dist/esnext/components/Money/MoneyFragment.d.ts +0 -8
- package/dist/esnext/components/Money/MoneyFragment.js +0 -1
- package/dist/esnext/components/ProductProvider/ProductProviderFragment.d.ts +0 -247
- package/dist/esnext/components/ProductProvider/ProductProviderFragment.js +0 -1
- package/dist/esnext/components/ProductProvider/types.d.ts +0 -19
- package/dist/esnext/components/ProductProvider/types.js +0 -1
- package/dist/esnext/components/RawHtml/RawHtml.d.ts +0 -17
- package/dist/esnext/components/RawHtml/RawHtml.js +0 -21
- package/dist/esnext/components/RawHtml/index.d.ts +0 -1
- package/dist/esnext/components/RawHtml/index.js +0 -1
- package/dist/esnext/components/Seo/SeoFragment.d.ts +0 -66
- package/dist/esnext/components/Seo/SeoFragment.js +0 -1
- package/dist/esnext/components/Seo/types.d.ts +0 -15
- package/dist/esnext/components/Seo/types.js +0 -1
- package/dist/esnext/components/UnitPrice/UnitPriceFragment.d.ts +0 -15
- package/dist/esnext/components/UnitPrice/UnitPriceFragment.js +0 -1
- package/dist/esnext/components/Video/VideoFragment.d.ts +0 -15
- package/dist/esnext/components/Video/VideoFragment.js +0 -1
- package/dist/esnext/foundation/Router/FileRoutes.d.ts +0 -18
- package/dist/esnext/foundation/Router/Route.server.d.ts +0 -9
- package/dist/esnext/foundation/Router/Route.server.js +0 -6
- package/dist/esnext/foundation/Router/useParams.d.ts +0 -1
- package/dist/esnext/foundation/Router/useParams.js +0 -5
- package/dist/esnext/fragments.d.ts +0 -20
- package/dist/esnext/fragments.js +0 -10
- package/dist/esnext/graphql/graphql-constants.d.ts +0 -1756
- package/dist/esnext/graphql/graphql-constants.js +0 -3447
- package/dist/esnext/hooks/useAvailableCountries/index.d.ts +0 -1
- package/dist/esnext/hooks/useAvailableCountries/index.js +0 -1
- package/dist/esnext/hooks/useAvailableCountries/useAvailableCountries.d.ts +0 -11
- package/dist/esnext/hooks/useAvailableCountries/useAvailableCountries.js +0 -17
- package/dist/esnext/hooks/useNavigate/index.d.ts +0 -1
- package/dist/esnext/hooks/useNavigate/index.js +0 -1
- package/dist/esnext/hooks/useProductOptions/SellingPlanFragment.d.ts +0 -31
- package/dist/esnext/hooks/useProductOptions/SellingPlanFragment.js +0 -1
- package/dist/esnext/hooks/useProductOptions/SellingPlanGroupsFragment.d.ts +0 -46
- package/dist/esnext/hooks/useProductOptions/SellingPlanGroupsFragment.js +0 -1
- package/dist/esnext/hooks/useProductOptions/VariantFragment.d.ts +0 -106
- package/dist/esnext/hooks/useProductOptions/VariantFragment.js +0 -1
- package/fragments.d.ts +0 -1
- package/fragments.js +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Scalars, Shop as ShopType, Seo as SeoType } from '../../storefront-api-types';
|
|
2
|
+
export interface Twitter {
|
|
3
|
+
site: string;
|
|
4
|
+
title: SeoType['title'];
|
|
5
|
+
description: SeoType['description'];
|
|
6
|
+
}
|
|
7
|
+
export interface HomePage {
|
|
8
|
+
description: ShopType['description'];
|
|
9
|
+
title: ShopType['name'];
|
|
10
|
+
url: Scalars['URL'];
|
|
11
|
+
}
|
|
12
|
+
export interface DefaultPage extends ShopType {
|
|
13
|
+
title: ShopType['name'];
|
|
14
|
+
url: Scalars['URL'];
|
|
15
|
+
titleTemplate?: string;
|
|
16
|
+
lang?: string;
|
|
17
|
+
}
|
|
File without changes
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnitPriceMeasurement, MoneyV2 } from '../../storefront-api-types';
|
|
2
|
+
import type { PartialDeep } from 'type-fest';
|
|
2
3
|
export interface UnitPriceProps<TTag> {
|
|
3
|
-
/**
|
|
4
|
-
data:
|
|
5
|
-
/** A [
|
|
6
|
-
measurement:
|
|
4
|
+
/** An object with fields that correspond to the Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2). */
|
|
5
|
+
data: PartialDeep<MoneyV2>;
|
|
6
|
+
/** A [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement). */
|
|
7
|
+
measurement: PartialDeep<UnitPriceMeasurement>;
|
|
7
8
|
/** An HTML tag to be rendered as the base element wrapper. The default is `div`. */
|
|
8
9
|
as?: TTag;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
|
|
12
|
-
*
|
|
13
|
+
* Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the Storefront API's [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement).
|
|
13
14
|
*/
|
|
14
15
|
export declare function UnitPrice<TTag extends keyof JSX.IntrinsicElements = 'div'>(props: JSX.IntrinsicElements[TTag] & UnitPriceProps<TTag>): JSX.Element | null;
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { Money } from '../Money';
|
|
3
3
|
/**
|
|
4
4
|
* The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
|
|
5
|
-
*
|
|
5
|
+
* Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the Storefront API's [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement).
|
|
6
6
|
*/
|
|
7
7
|
export function UnitPrice(props) {
|
|
8
8
|
const { data, measurement, as, ...passthroughProps } = props;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ImageSizeOptions } from '../../utilities';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Video as VideoType } from '../../storefront-api-types';
|
|
3
|
+
import type { PartialDeep } from 'type-fest';
|
|
3
4
|
interface VideoProps {
|
|
4
|
-
/** An object
|
|
5
|
-
data:
|
|
5
|
+
/** An object with fields that correspond to the Storefront API's [Video object](/api/storefront/latest/objects/video). */
|
|
6
|
+
data: PartialDeep<VideoType>;
|
|
6
7
|
/** An object of image size options for the video's `previewImage`. */
|
|
7
8
|
options?: ImageSizeOptions;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
|
-
* The `Video` component renders a `video` for the Storefront API's [
|
|
11
|
+
* The `Video` component renders a `video` for the Storefront API's [Video object](/api/storefront/reference/products/video).
|
|
11
12
|
*/
|
|
12
13
|
export declare function Video(props: JSX.IntrinsicElements['video'] & VideoProps): JSX.Element;
|
|
13
14
|
export {};
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useImageUrl } from '../../utilities';
|
|
3
3
|
/**
|
|
4
|
-
* The `Video` component renders a `video` for the Storefront API's [
|
|
4
|
+
* The `Video` component renders a `video` for the Storefront API's [Video object](/api/storefront/reference/products/video).
|
|
5
5
|
*/
|
|
6
6
|
export function Video(props) {
|
|
7
7
|
var _a;
|
|
8
8
|
const { data, options, id = data.id, playsInline = true, controls = true, ...passthroughProps } = props;
|
|
9
9
|
const posterUrl = useImageUrl((_a = data.previewImage) === null || _a === void 0 ? void 0 : _a.url, options);
|
|
10
|
-
|
|
10
|
+
if (!data.sources) {
|
|
11
|
+
throw new Error(`<Video/> requires a 'data.sources' array`);
|
|
12
|
+
}
|
|
13
|
+
return (React.createElement("video", { ...passthroughProps, id: id, playsInline: playsInline, controls: controls, poster: posterUrl }, data.sources.map((source) => {
|
|
14
|
+
if (!((source === null || source === void 0 ? void 0 : source.url) && (source === null || source === void 0 ? void 0 : source.mimeType))) {
|
|
15
|
+
throw new Error(`<Video/> needs 'source.url' and 'source.mimeType'`);
|
|
16
|
+
}
|
|
17
|
+
return (React.createElement("source", { key: source.url, src: source.url, type: source.mimeType }));
|
|
18
|
+
})));
|
|
11
19
|
}
|
|
@@ -3,7 +3,6 @@ export { MediaFile } from './MediaFile';
|
|
|
3
3
|
export { Video } from './Video';
|
|
4
4
|
export { Image } from './Image';
|
|
5
5
|
export { ExternalVideo } from './ExternalVideo';
|
|
6
|
-
export { RawHtml } from './RawHtml';
|
|
7
6
|
export { AddToCartButton } from './AddToCartButton';
|
|
8
7
|
export { ModelViewer } from './ModelViewer';
|
|
9
8
|
export { Money } from './Money';
|
|
@@ -28,7 +27,5 @@ export { ProductPrice } from './ProductPrice';
|
|
|
28
27
|
export { ProductMetafield } from './ProductMetafield';
|
|
29
28
|
export { BuyNowButton } from './BuyNowButton';
|
|
30
29
|
export { ShopPayButton } from './ShopPayButton';
|
|
31
|
-
export { useAvailableCountries } from '../hooks/useAvailableCountries';
|
|
32
30
|
export { useCountry } from '../hooks/useCountry';
|
|
33
31
|
export { Seo } from './Seo';
|
|
34
|
-
export { useNavigate } from '../hooks/useNavigate';
|
|
@@ -3,7 +3,6 @@ export { MediaFile } from './MediaFile';
|
|
|
3
3
|
export { Video } from './Video';
|
|
4
4
|
export { Image } from './Image';
|
|
5
5
|
export { ExternalVideo } from './ExternalVideo';
|
|
6
|
-
export { RawHtml } from './RawHtml';
|
|
7
6
|
export { AddToCartButton } from './AddToCartButton';
|
|
8
7
|
export { ModelViewer } from './ModelViewer';
|
|
9
8
|
export { Money } from './Money';
|
|
@@ -26,7 +25,5 @@ export { ProductPrice } from './ProductPrice';
|
|
|
26
25
|
export { ProductMetafield } from './ProductMetafield';
|
|
27
26
|
export { BuyNowButton } from './BuyNowButton';
|
|
28
27
|
export { ShopPayButton } from './ShopPayButton';
|
|
29
|
-
export { useAvailableCountries } from '../hooks/useAvailableCountries';
|
|
30
28
|
export { useCountry } from '../hooks/useCountry';
|
|
31
29
|
export { Seo } from './Seo';
|
|
32
|
-
export { useNavigate } from '../hooks/useNavigate';
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import React, { Suspense, useState, StrictMode, Fragment, } from 'react';
|
|
2
2
|
// @ts-expect-error hydrateRoot isn't on the TS types yet, but we're using React 18 so it exists
|
|
3
|
-
import { hydrateRoot } from 'react-dom';
|
|
3
|
+
import { hydrateRoot } from 'react-dom/client';
|
|
4
4
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
5
5
|
import { useServerResponse } from './framework/Hydration/rsc';
|
|
6
6
|
import { ServerStateProvider } from './foundation/ServerStateProvider';
|
|
7
|
-
import { Router } from './foundation/Router/Router';
|
|
8
7
|
const renderHydrogen = async (ClientWrapper, config) => {
|
|
9
8
|
const root = document.getElementById('root');
|
|
10
9
|
if (!root) {
|
|
11
10
|
console.error(`Could not find a root element <div id="root"></div> to render.`);
|
|
12
11
|
return;
|
|
13
12
|
}
|
|
13
|
+
if (import.meta.hot) {
|
|
14
|
+
import.meta.hot.on('hydrogen', ({ type, data }) => {
|
|
15
|
+
if (type === 'warn') {
|
|
16
|
+
console.warn(data);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
14
20
|
// default to StrictMode on, unless explicitly turned off
|
|
15
21
|
const RootComponent = (config === null || config === void 0 ? void 0 : config.strictMode) !== false ? StrictMode : Fragment;
|
|
16
22
|
hydrateRoot(root, React.createElement(RootComponent, null,
|
|
@@ -26,8 +32,7 @@ function Content({ clientWrapper: ClientWrapper = ({ children }) => children, })
|
|
|
26
32
|
});
|
|
27
33
|
const response = useServerResponse(serverState);
|
|
28
34
|
return (React.createElement(ServerStateProvider, { serverState: serverState, setServerState: setServerState },
|
|
29
|
-
React.createElement(
|
|
30
|
-
React.createElement(ClientWrapper, null, response.readRoot()))));
|
|
35
|
+
React.createElement(ClientWrapper, null, response.readRoot())));
|
|
31
36
|
}
|
|
32
37
|
function Error({ error }) {
|
|
33
38
|
if (import.meta.env.DEV) {
|
|
@@ -14,6 +14,7 @@ interface RequestHandlerOptions {
|
|
|
14
14
|
dev?: boolean;
|
|
15
15
|
context?: RuntimeContext;
|
|
16
16
|
nonce?: string;
|
|
17
|
+
buyerIpHeader?: string;
|
|
17
18
|
}
|
|
18
19
|
export interface RequestHandler {
|
|
19
20
|
(request: Request | IncomingMessage, options: RequestHandlerOptions): Promise<Response | undefined>;
|
|
@@ -15,10 +15,13 @@ import { setConfig } from './framework/config';
|
|
|
15
15
|
import { ssrRenderToPipeableStream, ssrRenderToReadableStream, rscRenderToReadableStream, createFromReadableStream, isStreamingSupported, bufferReadableStream, } from './streaming.server';
|
|
16
16
|
import { RSC_PATHNAME } from './constants';
|
|
17
17
|
import { stripScriptsFromTemplate } from './utilities/template';
|
|
18
|
+
const DOCTYPE = '<!DOCTYPE html>';
|
|
19
|
+
const CONTENT_TYPE = 'Content-Type';
|
|
18
20
|
const HTML_CONTENT_TYPE = 'text/html; charset=UTF-8';
|
|
19
21
|
export const renderHydrogen = (App, { shopifyConfig, routes }) => {
|
|
20
|
-
const handleRequest = async function (rawRequest, { indexTemplate, streamableResponse, dev, cache, context, nonce }) {
|
|
22
|
+
const handleRequest = async function (rawRequest, { indexTemplate, streamableResponse, dev, cache, context, nonce, buyerIpHeader, }) {
|
|
21
23
|
const request = new ServerComponentRequest(rawRequest);
|
|
24
|
+
request.ctx.buyerIpHeader = buyerIpHeader;
|
|
22
25
|
const url = new URL(request.url);
|
|
23
26
|
const log = getLoggerWithContext(request);
|
|
24
27
|
const componentResponse = new ServerComponentResponse();
|
|
@@ -92,9 +95,14 @@ async function render(url, { App, routes, request, componentResponse, log, templ
|
|
|
92
95
|
routes,
|
|
93
96
|
log,
|
|
94
97
|
}, { template });
|
|
98
|
+
function onErrorShell(error) {
|
|
99
|
+
log.error(error);
|
|
100
|
+
componentResponse.writeHead({ status: 500 });
|
|
101
|
+
return template;
|
|
102
|
+
}
|
|
95
103
|
let [html, flight] = await Promise.all([
|
|
96
|
-
renderToBufferedString(AppSSR, { log, nonce }),
|
|
97
|
-
bufferReadableStream(rscReadable.getReader()),
|
|
104
|
+
renderToBufferedString(AppSSR, { log, nonce }).catch(onErrorShell),
|
|
105
|
+
bufferReadableStream(rscReadable.getReader()).catch(() => null),
|
|
98
106
|
]);
|
|
99
107
|
const { headers, status, statusText } = getResponseOptions(componentResponse);
|
|
100
108
|
/**
|
|
@@ -111,7 +119,7 @@ async function render(url, { App, routes, request, componentResponse, log, templ
|
|
|
111
119
|
headers,
|
|
112
120
|
});
|
|
113
121
|
}
|
|
114
|
-
headers[
|
|
122
|
+
headers[CONTENT_TYPE] = HTML_CONTENT_TYPE;
|
|
115
123
|
html = applyHtmlHead(html, request.ctx.head, template);
|
|
116
124
|
if (flight) {
|
|
117
125
|
html = html.replace('</body>', `${flightContainer({ init: true, nonce, chunk: flight })}</body>`);
|
|
@@ -128,6 +136,7 @@ async function render(url, { App, routes, request, componentResponse, log, templ
|
|
|
128
136
|
* information, so this method should not be used by crawlers.
|
|
129
137
|
*/
|
|
130
138
|
async function stream(url, { App, routes, request, response, componentResponse, log, template, nonce, dev, }) {
|
|
139
|
+
var _a;
|
|
131
140
|
const state = { pathname: url.pathname, search: url.search };
|
|
132
141
|
log.trace('start stream');
|
|
133
142
|
const { noScriptTemplate, bootstrapScripts, bootstrapModules } = stripScriptsFromTemplate(template);
|
|
@@ -156,59 +165,66 @@ async function stream(url, { App, routes, request, response, componentResponse,
|
|
|
156
165
|
});
|
|
157
166
|
let didError;
|
|
158
167
|
if (__WORKER__) {
|
|
159
|
-
const
|
|
168
|
+
const onCompleteAll = defer();
|
|
160
169
|
const encoder = new TextEncoder();
|
|
161
170
|
const transform = new TransformStream();
|
|
162
171
|
const writable = transform.writable.getWriter();
|
|
163
172
|
const responseOptions = {};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
173
|
+
let ssrReadable;
|
|
174
|
+
try {
|
|
175
|
+
ssrReadable = await ssrRenderToReadableStream(AppSSR, {
|
|
176
|
+
nonce,
|
|
177
|
+
bootstrapScripts,
|
|
178
|
+
bootstrapModules,
|
|
179
|
+
onError(error) {
|
|
180
|
+
didError = error;
|
|
181
|
+
if (dev && !writable.closed && !!responseOptions.status) {
|
|
182
|
+
writable.write(getErrorMarkup(error));
|
|
183
|
+
}
|
|
184
|
+
log.error(error);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
log.error(error);
|
|
190
|
+
return new Response(template + (dev ? getErrorMarkup(error) : ''), {
|
|
191
|
+
status: 500,
|
|
192
|
+
headers: { [CONTENT_TYPE]: HTML_CONTENT_TYPE },
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
log.trace('worker ready to stream');
|
|
196
|
+
ssrReadable.allReady.then(() => {
|
|
197
|
+
log.trace('worker complete stream');
|
|
198
|
+
onCompleteAll.resolve(true);
|
|
199
|
+
});
|
|
200
|
+
async function prepareForStreaming(flush) {
|
|
201
|
+
Object.assign(responseOptions, getResponseOptions(componentResponse, didError));
|
|
202
|
+
/**
|
|
203
|
+
* TODO: This assumes `response.cache()` has been called _before_ any
|
|
204
|
+
* queries which might be caught behind Suspense. Clarify this or add
|
|
205
|
+
* additional checks downstream?
|
|
206
|
+
*/
|
|
207
|
+
responseOptions.headers[getCacheControlHeader({ dev })] =
|
|
208
|
+
componentResponse.cacheControlHeader;
|
|
209
|
+
if (isRedirect(responseOptions)) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
if (flush) {
|
|
196
213
|
if (componentResponse.customBody) {
|
|
197
214
|
writable.write(encoder.encode(await componentResponse.customBody));
|
|
198
|
-
return
|
|
215
|
+
return false;
|
|
199
216
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (dev && deferredShouldReturnApp.status === 'pending') {
|
|
206
|
-
writable.write(getErrorMarkup(error));
|
|
217
|
+
responseOptions.headers[CONTENT_TYPE] = HTML_CONTENT_TYPE;
|
|
218
|
+
writable.write(encoder.encode(DOCTYPE));
|
|
219
|
+
if (didError) {
|
|
220
|
+
// This error was delayed until the headers were properly sent.
|
|
221
|
+
writable.write(encoder.encode(getErrorMarkup(didError)));
|
|
207
222
|
}
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const shouldReturnApp = (_a = (await prepareForStreaming(componentResponse.canStream()))) !== null && _a !== void 0 ? _a : (await onCompleteAll.promise.then(prepareForStreaming));
|
|
227
|
+
if (shouldReturnApp) {
|
|
212
228
|
let bufferedSsr = '';
|
|
213
229
|
let isPendingSsrWrite = false;
|
|
214
230
|
const writingSSR = bufferReadableStream(ssrReadable.getReader(), (chunk) => {
|
|
@@ -245,12 +261,11 @@ async function stream(url, { App, routes, request, response, componentResponse,
|
|
|
245
261
|
return new Response(bufferedBody, responseOptions);
|
|
246
262
|
}
|
|
247
263
|
else if (response) {
|
|
248
|
-
response.socket.on('error', log.fatal);
|
|
249
264
|
const { pipe } = ssrRenderToPipeableStream(AppSSR, {
|
|
250
265
|
nonce,
|
|
251
266
|
bootstrapScripts,
|
|
252
267
|
bootstrapModules,
|
|
253
|
-
|
|
268
|
+
onShellReady() {
|
|
254
269
|
log.trace('node ready to stream');
|
|
255
270
|
/**
|
|
256
271
|
* TODO: This assumes `response.cache()` has been called _before_ any
|
|
@@ -275,7 +290,7 @@ async function stream(url, { App, routes, request, response, componentResponse,
|
|
|
275
290
|
return response.write(chunk);
|
|
276
291
|
});
|
|
277
292
|
},
|
|
278
|
-
async
|
|
293
|
+
async onAllReady() {
|
|
279
294
|
log.trace('node complete stream');
|
|
280
295
|
if (componentResponse.canStream() || response.writableEnded) {
|
|
281
296
|
postRequestTasks('str', response.statusCode, request, componentResponse);
|
|
@@ -298,6 +313,15 @@ async function stream(url, { App, routes, request, response, componentResponse,
|
|
|
298
313
|
pipe(response);
|
|
299
314
|
});
|
|
300
315
|
},
|
|
316
|
+
onShellError(error) {
|
|
317
|
+
log.error(error);
|
|
318
|
+
if (!response.writableEnded) {
|
|
319
|
+
writeHeadToServerResponse(response, componentResponse, log, error);
|
|
320
|
+
startWritingHtmlToServerResponse(response, dev ? error : undefined);
|
|
321
|
+
response.write(template);
|
|
322
|
+
response.end();
|
|
323
|
+
}
|
|
324
|
+
},
|
|
301
325
|
onError(error) {
|
|
302
326
|
didError = error;
|
|
303
327
|
if (dev && response.headersSent) {
|
|
@@ -335,7 +359,6 @@ async function hydrate(url, { App, routes, request, response, componentResponse,
|
|
|
335
359
|
return new Response(bufferedBody);
|
|
336
360
|
}
|
|
337
361
|
else if (response) {
|
|
338
|
-
response.socket.on('error', log.fatal);
|
|
339
362
|
const rscWriter = await import(
|
|
340
363
|
// @ts-ignore
|
|
341
364
|
'@shopify/hydrogen/vendor/react-server-dom-vite/writer.node.server');
|
|
@@ -349,9 +372,11 @@ async function hydrate(url, { App, routes, request, response, componentResponse,
|
|
|
349
372
|
}
|
|
350
373
|
function buildAppRSC({ App, state, request, response, log, routes, }) {
|
|
351
374
|
const hydrogenServerProps = { request, response, log };
|
|
375
|
+
const serverProps = { ...state, ...hydrogenServerProps, routes };
|
|
376
|
+
request.ctx.router.serverProps = serverProps;
|
|
352
377
|
const AppRSC = (React.createElement(ServerRequestProvider, { request: request, isRSC: true },
|
|
353
378
|
React.createElement(PreloadQueries, { request: request },
|
|
354
|
-
React.createElement(App, { ...
|
|
379
|
+
React.createElement(App, { ...serverProps }))));
|
|
355
380
|
return { AppRSC };
|
|
356
381
|
}
|
|
357
382
|
function buildAppSSR({ App, state, request, response, log, routes }, htmlOptions) {
|
|
@@ -382,25 +407,23 @@ function PreloadQueries({ request, children, }) {
|
|
|
382
407
|
async function renderToBufferedString(ReactApp, { log, nonce }) {
|
|
383
408
|
return new Promise(async (resolve, reject) => {
|
|
384
409
|
if (__WORKER__) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
await deferred.promise.catch(reject);
|
|
403
|
-
resolve(await bufferReadableStream(readable.getReader()));
|
|
410
|
+
try {
|
|
411
|
+
const ssrReadable = await ssrRenderToReadableStream(ReactApp, {
|
|
412
|
+
nonce,
|
|
413
|
+
onError: (error) => log.error(error),
|
|
414
|
+
});
|
|
415
|
+
/**
|
|
416
|
+
* We want to wait until `allReady` resolves before fetching the
|
|
417
|
+
* stream body. Otherwise, React 18's streaming JS script/template tags
|
|
418
|
+
* will be included in the output and cause issues when loading
|
|
419
|
+
* the Client Components in the browser.
|
|
420
|
+
*/
|
|
421
|
+
await ssrReadable.allReady;
|
|
422
|
+
resolve(bufferReadableStream(ssrReadable.getReader()));
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
reject(error);
|
|
426
|
+
}
|
|
404
427
|
}
|
|
405
428
|
else {
|
|
406
429
|
const writer = await createNodeWriter();
|
|
@@ -410,7 +433,7 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
|
|
|
410
433
|
* When hydrating, we have to wait until `onCompleteAll` to avoid having
|
|
411
434
|
* `template` and `script` tags inserted and rendered as part of the hydration response.
|
|
412
435
|
*/
|
|
413
|
-
|
|
436
|
+
onAllReady() {
|
|
414
437
|
let data = '';
|
|
415
438
|
writer.on('data', (chunk) => (data += chunk.toString()));
|
|
416
439
|
writer.once('error', reject);
|
|
@@ -418,10 +441,8 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
|
|
|
418
441
|
// Tell React to start writing to the writer
|
|
419
442
|
pipe(writer);
|
|
420
443
|
},
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
reject(error);
|
|
424
|
-
},
|
|
444
|
+
onShellError: reject,
|
|
445
|
+
onError: (error) => log.error(error),
|
|
425
446
|
});
|
|
426
447
|
}
|
|
427
448
|
});
|
|
@@ -429,22 +450,14 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
|
|
|
429
450
|
export default renderHydrogen;
|
|
430
451
|
function startWritingHtmlToServerResponse(response, error) {
|
|
431
452
|
if (!response.headersSent) {
|
|
432
|
-
response.setHeader(
|
|
433
|
-
response.write(
|
|
453
|
+
response.setHeader(CONTENT_TYPE, HTML_CONTENT_TYPE);
|
|
454
|
+
response.write(DOCTYPE);
|
|
434
455
|
}
|
|
435
456
|
if (error) {
|
|
436
457
|
// This error was delayed until the headers were properly sent.
|
|
437
458
|
response.write(getErrorMarkup(error));
|
|
438
459
|
}
|
|
439
460
|
}
|
|
440
|
-
function startWritingHtmlToStream(responseOptions, writable, encoder, error) {
|
|
441
|
-
responseOptions.headers['Content-type'] = HTML_CONTENT_TYPE;
|
|
442
|
-
writable.write(encoder.encode('<!DOCTYPE html>'));
|
|
443
|
-
if (error) {
|
|
444
|
-
// This error was delayed until the headers were properly sent.
|
|
445
|
-
writable.write(encoder.encode(getErrorMarkup(error)));
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
461
|
function getResponseOptions({ headers, status, customStatus }, error) {
|
|
449
462
|
var _a, _b;
|
|
450
463
|
const responseInit = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ImportGlobEagerOutput } from '../../types';
|
|
2
|
+
interface FileRoutesProps {
|
|
3
|
+
/** The routes defined by Vite's [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. */
|
|
4
|
+
routes: ImportGlobEagerOutput;
|
|
5
|
+
/** A path that's prepended to all file routes. You can modify `basePath` if you want to prefix all file routes. For example, you can prefix all file routes with a locale. */
|
|
6
|
+
basePath?: string;
|
|
7
|
+
/** The portion of the file route path that shouldn't be a part of the URL. You need to modify this if you want to import routes from a location other than the default `src/routes`. */
|
|
8
|
+
dirPrefix?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The `FileRoutes` component builds a set of default Hydrogen routes based on the output provided by Vite's
|
|
12
|
+
* [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple
|
|
13
|
+
* instances of this component to source file routes from multiple locations.
|
|
14
|
+
*/
|
|
15
|
+
export declare function FileRoutes({ routes, basePath, dirPrefix, }: FileRoutesProps): JSX.Element | null;
|
|
16
|
+
interface HydrogenRoute {
|
|
17
|
+
component: any;
|
|
18
|
+
path: string;
|
|
19
|
+
exact: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function createPageRoutes(pages: ImportGlobEagerOutput, topLevelPath: string | undefined, dirPrefix: string): HydrogenRoute[];
|
|
22
|
+
export {};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { matchPath } from '../../utilities/matchPath';
|
|
3
3
|
import { log } from '../../utilities/log';
|
|
4
|
+
import { useServerRequest } from '../ServerRequestProvider';
|
|
5
|
+
import { RouteParamsProvider } from '../useRouteParams/RouteParamsProvider.client';
|
|
4
6
|
/**
|
|
5
|
-
*
|
|
6
|
-
* import.meta.globEager method.
|
|
7
|
-
*
|
|
8
|
-
* @see https://vitejs.dev/guide/features.html#glob-import
|
|
7
|
+
* The `FileRoutes` component builds a set of default Hydrogen routes based on the output provided by Vite's
|
|
8
|
+
* [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple
|
|
9
|
+
* instances of this component to source file routes from multiple locations.
|
|
9
10
|
*/
|
|
10
|
-
export function FileRoutes({ routes,
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
export function FileRoutes({ routes, basePath = '/', dirPrefix = './routes', }) {
|
|
12
|
+
const request = useServerRequest();
|
|
13
|
+
const { routeRendered, serverProps } = request.ctx.router;
|
|
14
|
+
if (routeRendered)
|
|
15
|
+
return null;
|
|
16
|
+
const pageRoutes = useMemo(() => createPageRoutes(routes, basePath, dirPrefix), [routes, basePath]);
|
|
13
17
|
let foundRoute, foundRouteDetails;
|
|
14
18
|
for (let i = 0; i < pageRoutes.length; i++) {
|
|
15
19
|
foundRouteDetails = matchPath(serverProps.pathname, pageRoutes[i]);
|
|
@@ -18,14 +22,20 @@ export function FileRoutes({ routes, serverProps, }) {
|
|
|
18
22
|
break;
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
|
-
|
|
25
|
+
if (foundRoute) {
|
|
26
|
+
request.ctx.router.routeRendered = true;
|
|
27
|
+
request.ctx.router.routeParams = foundRouteDetails.params;
|
|
28
|
+
return (React.createElement(RouteParamsProvider, { routeParams: foundRouteDetails.params },
|
|
29
|
+
React.createElement(foundRoute.component, { params: foundRouteDetails.params, ...serverProps })));
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
22
32
|
}
|
|
23
|
-
export function createPageRoutes(pages, topLevelPath = '*') {
|
|
33
|
+
export function createPageRoutes(pages, topLevelPath = '*', dirPrefix) {
|
|
24
34
|
const topLevelPrefix = topLevelPath.replace('*', '').replace(/\/$/, '');
|
|
25
35
|
const routes = Object.keys(pages)
|
|
26
36
|
.map((key) => {
|
|
27
37
|
let path = key
|
|
28
|
-
.replace(
|
|
38
|
+
.replace(dirPrefix, '')
|
|
29
39
|
.replace(/\.server\.(t|j)sx?$/, '')
|
|
30
40
|
/**
|
|
31
41
|
* Replace /index with /
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useNavigate } from '../../foundation/useNavigate/useNavigate';
|
|
3
|
+
export default function Redirect({ to }) {
|
|
4
|
+
const navigate = useNavigate();
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (to.startsWith('http')) {
|
|
7
|
+
window.location.href = to;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
navigate(to);
|
|
11
|
+
}
|
|
12
|
+
}, []);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
export declare type RouteProps = {
|
|
3
|
+
/** The URL path where the route exists. The path can contain variables. For example, `/products/:handle`. */
|
|
4
|
+
path: string;
|
|
5
|
+
/** A reference to a React Server Component that's rendered when the route is active. */
|
|
6
|
+
page: ReactElement;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The `Route` component is used to set up a route in Hydrogen that's independent of the file system. Routes are
|
|
10
|
+
* matched in the order that they're defined.
|
|
11
|
+
*/
|
|
12
|
+
export declare function Route({ path, page }: RouteProps): ReactElement | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { cloneElement } from 'react';
|
|
2
|
+
import { useServerRequest } from '../ServerRequestProvider';
|
|
3
|
+
import { matchPath } from '../../utilities/matchPath';
|
|
4
|
+
import { Boomerang } from '../Boomerang/Boomerang.client';
|
|
5
|
+
import { RouteParamsProvider } from '../useRouteParams/RouteParamsProvider.client';
|
|
6
|
+
/**
|
|
7
|
+
* The `Route` component is used to set up a route in Hydrogen that's independent of the file system. Routes are
|
|
8
|
+
* matched in the order that they're defined.
|
|
9
|
+
*/
|
|
10
|
+
export function Route({ path, page }) {
|
|
11
|
+
var _a;
|
|
12
|
+
const request = useServerRequest();
|
|
13
|
+
const { routeRendered, serverProps } = request.ctx.router;
|
|
14
|
+
if (routeRendered)
|
|
15
|
+
return null;
|
|
16
|
+
if (path === '*') {
|
|
17
|
+
request.ctx.router.routeRendered = true;
|
|
18
|
+
return cloneElement(page, serverProps);
|
|
19
|
+
}
|
|
20
|
+
const match = matchPath(serverProps.pathname, {
|
|
21
|
+
path,
|
|
22
|
+
exact: true,
|
|
23
|
+
});
|
|
24
|
+
if (match) {
|
|
25
|
+
request.ctx.router.routeRendered = true;
|
|
26
|
+
request.ctx.router.routeParams = match.params;
|
|
27
|
+
const name = (_a = page === null || page === void 0 ? void 0 : page.type) === null || _a === void 0 ? void 0 : _a.name;
|
|
28
|
+
return (React.createElement(RouteParamsProvider, { routeParams: match.params },
|
|
29
|
+
cloneElement(page, { params: match.params || {}, ...serverProps }),
|
|
30
|
+
name ? React.createElement(Boomerang, { pageTemplate: name }) : null));
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|