@shopify/hydrogen 1.0.0 → 1.1.0
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/esnext/client.d.ts +4 -4
- package/dist/esnext/client.js +4 -4
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +1 -1
- package/dist/esnext/components/CartProvider/hooks.client.js +8 -1
- package/dist/esnext/components/Image/Image.js +22 -13
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.d.ts +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +3 -2
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +6 -10
- package/dist/esnext/components/ProductOptionsProvider/context.d.ts +1 -1
- package/dist/esnext/components/ProductOptionsProvider/index.d.ts +0 -1
- package/dist/esnext/components/ProductOptionsProvider/index.js +0 -1
- package/dist/esnext/components/index.d.ts +1 -2
- package/dist/esnext/components/index.js +1 -2
- package/dist/esnext/constants.d.ts +4 -0
- package/dist/esnext/constants.js +4 -0
- package/dist/esnext/entry-server.js +10 -9
- package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js +4 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.client.js +2 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server.js +1 -1
- package/dist/esnext/foundation/Analytics/connectors/Shopify/const.d.ts +0 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/const.js +0 -2
- package/dist/esnext/foundation/DevTools/components/Heading.js +1 -1
- package/dist/esnext/foundation/DevTools/components/Panels.js +25 -19
- package/dist/esnext/foundation/DevTools/components/Performance.client.js +0 -1
- package/dist/esnext/foundation/DevTools/components/Settings.client.js +1 -4
- package/dist/esnext/foundation/DevTools/components/Table.js +3 -3
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.d.ts +1 -2
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.js +2 -4
- package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +3 -3
- package/dist/esnext/foundation/ServerPropsProvider/index.d.ts +1 -2
- package/dist/esnext/foundation/ServerPropsProvider/index.js +1 -1
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.js +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +19 -2
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +17 -0
- package/dist/esnext/foundation/fetchSync/ResponseSync.d.ts +14 -0
- package/dist/esnext/foundation/fetchSync/ResponseSync.js +38 -0
- package/dist/esnext/foundation/fetchSync/client/fetchSync.d.ts +2 -2
- package/dist/esnext/foundation/fetchSync/client/fetchSync.js +5 -10
- package/dist/esnext/foundation/fetchSync/server/fetchSync.d.ts +2 -2
- package/dist/esnext/foundation/fetchSync/server/fetchSync.js +9 -12
- package/dist/esnext/framework/graphiql.js +26 -30
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +35 -6
- package/dist/esnext/hooks/index.d.ts +1 -0
- package/dist/esnext/hooks/index.js +1 -0
- package/dist/esnext/hooks/useLocalization/useLocalization.d.ts +3 -2
- package/dist/esnext/hooks/useLocalization/useLocalization.js +2 -7
- package/dist/esnext/hooks/useProductOptions/helpers.js +1 -1
- package/dist/esnext/hooks/useShopQuery/hooks.js +9 -6
- package/dist/esnext/index.d.ts +6 -5
- package/dist/esnext/index.js +6 -5
- package/dist/esnext/platforms/index.d.ts +1 -0
- package/dist/esnext/platforms/index.js +1 -0
- package/dist/esnext/platforms/node.js +2 -8
- package/dist/esnext/platforms/virtual.d.ts +8 -0
- package/dist/esnext/platforms/virtual.js +14 -0
- package/dist/esnext/platforms/worker.js +7 -7
- package/dist/esnext/utilities/image_size.d.ts +1 -0
- package/dist/esnext/utilities/image_size.js +27 -26
- package/dist/esnext/utilities/index.d.ts +1 -1
- package/dist/esnext/utilities/index.js +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/graphiql.js +26 -30
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +35 -6
- package/package.json +7 -2
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +26 -12
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +26 -12
- package/CHANGELOG.md +0 -2198
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -9
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.js +0 -2
- package/dist/esnext/foundation/fetchSync/types.d.ts +0 -5
- package/dist/esnext/foundation/fetchSync/types.js +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { createContext } from 'react';
|
|
2
2
|
export const ShopifyContext = createContext(null);
|
|
3
|
-
export
|
|
3
|
+
export const LocalizationContext = createContext(null);
|
|
4
|
+
export function ShopifyProviderClient({ children, shopifyConfig, localization, }) {
|
|
4
5
|
if (!shopifyConfig) {
|
|
5
6
|
throw new Error('The `shopifyConfig` prop should be passed to `ShopifyProvider`');
|
|
6
7
|
}
|
|
7
|
-
return (React.createElement(ShopifyContext.Provider, { value: shopifyConfig },
|
|
8
|
+
return (React.createElement(ShopifyContext.Provider, { value: shopifyConfig },
|
|
9
|
+
React.createElement(LocalizationContext.Provider, { value: localization }, children)));
|
|
8
10
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ShopifyProviderProps } from './types';
|
|
1
|
+
import type { ShopifyProviderProps, LocalizationContextValue } from './types';
|
|
2
|
+
import type { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export declare const SHOPIFY_PROVIDER_CONTEXT_KEY: unique symbol;
|
|
3
4
|
/**
|
|
4
5
|
* The `ShopifyProvider` component wraps your entire app and provides support for hooks.
|
|
@@ -11,6 +12,7 @@ export declare function ShopifyProvider({
|
|
|
11
12
|
* Shopify connection information. Defaults to
|
|
12
13
|
* [the `shopify` property in the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
|
|
13
14
|
*/
|
|
14
|
-
shopifyConfig,
|
|
15
|
+
shopifyConfig, countryCode, languageCode,
|
|
15
16
|
/** Any `ReactNode` elements. */
|
|
16
17
|
children, }: ShopifyProviderProps): JSX.Element;
|
|
18
|
+
export declare function getLocalizationContextValue(defaultLanguageCode: `${LanguageCode}`, defaultCountryCode: `${CountryCode}`, languageCode?: `${LanguageCode}`, countryCode?: `${CountryCode}`): LocalizationContextValue;
|
|
@@ -30,7 +30,7 @@ export function ShopifyProvider({
|
|
|
30
30
|
* Shopify connection information. Defaults to
|
|
31
31
|
* [the `shopify` property in the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
|
|
32
32
|
*/
|
|
33
|
-
shopifyConfig,
|
|
33
|
+
shopifyConfig, countryCode, languageCode,
|
|
34
34
|
/** Any `ReactNode` elements. */
|
|
35
35
|
children, }) {
|
|
36
36
|
const request = useServerRequest();
|
|
@@ -55,6 +55,23 @@ children, }) {
|
|
|
55
55
|
actualShopifyConfig = shopifyConfig;
|
|
56
56
|
}
|
|
57
57
|
const shopifyProviderValue = useMemo(() => makeShopifyContext(actualShopifyConfig), [actualShopifyConfig]);
|
|
58
|
+
const localization = getLocalizationContextValue(shopifyProviderValue.defaultLanguageCode, shopifyProviderValue.defaultCountryCode, languageCode, countryCode);
|
|
59
|
+
request.ctx.localization = localization;
|
|
58
60
|
request.ctx.shopifyConfig = shopifyProviderValue;
|
|
59
|
-
return (React.createElement(ShopifyProviderClient, { shopifyConfig: shopifyProviderValue }, children));
|
|
61
|
+
return (React.createElement(ShopifyProviderClient, { shopifyConfig: shopifyProviderValue, localization: localization }, children));
|
|
62
|
+
}
|
|
63
|
+
export function getLocalizationContextValue(defaultLanguageCode, defaultCountryCode, languageCode, countryCode) {
|
|
64
|
+
return useMemo(() => {
|
|
65
|
+
const runtimeLanguageCode = (languageCode ?? defaultLanguageCode).toUpperCase();
|
|
66
|
+
const runtimeCountryCode = (countryCode ?? defaultCountryCode).toUpperCase();
|
|
67
|
+
return {
|
|
68
|
+
country: {
|
|
69
|
+
isoCode: runtimeCountryCode,
|
|
70
|
+
},
|
|
71
|
+
language: {
|
|
72
|
+
isoCode: runtimeLanguageCode,
|
|
73
|
+
},
|
|
74
|
+
locale: `${runtimeLanguageCode}-${runtimeCountryCode}`,
|
|
75
|
+
};
|
|
76
|
+
}, [defaultLanguageCode, defaultCountryCode, countryCode, languageCode]);
|
|
60
77
|
}
|
|
@@ -6,9 +6,26 @@ export interface ShopifyContextValue extends Omit<ShopifyConfig, 'defaultLanguag
|
|
|
6
6
|
defaultCountryCode: `${CountryCode}`;
|
|
7
7
|
storefrontId: string | null;
|
|
8
8
|
}
|
|
9
|
+
export interface LocalizationContextValue {
|
|
10
|
+
country: {
|
|
11
|
+
isoCode: `${CountryCode}`;
|
|
12
|
+
};
|
|
13
|
+
language: {
|
|
14
|
+
isoCode: `${LanguageCode}`;
|
|
15
|
+
};
|
|
16
|
+
locale: `${LanguageCode}-${CountryCode}`;
|
|
17
|
+
}
|
|
9
18
|
export declare type ShopifyProviderProps = {
|
|
10
19
|
/** Shopify connection information. Defaults to the `shopify` property in the `hydrogen.config.js` file. */
|
|
11
20
|
shopifyConfig?: ShopifyConfig | ShopifyConfigFetcher;
|
|
12
21
|
/** Any `ReactNode` elements. */
|
|
13
22
|
children?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Override the `isoCode` to define the active country
|
|
25
|
+
*/
|
|
26
|
+
countryCode?: `${CountryCode}`;
|
|
27
|
+
/**
|
|
28
|
+
* Override the `languageCode` to define the active language
|
|
29
|
+
*/
|
|
30
|
+
languageCode?: `${LanguageCode}`;
|
|
14
31
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare type ResponseSyncInit = [string, ResponseInit];
|
|
2
|
+
export declare class ResponseSync extends Response {
|
|
3
|
+
#private;
|
|
4
|
+
bodyUsed: boolean;
|
|
5
|
+
constructor(init: ResponseSyncInit);
|
|
6
|
+
text(): string;
|
|
7
|
+
json(): any;
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Access response properties at the top level instead.
|
|
10
|
+
*/
|
|
11
|
+
get response(): this;
|
|
12
|
+
static toSerializable(response: Response): Promise<ResponseSyncInit>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { parseJSON } from '../../utilities/parse';
|
|
2
|
+
import { log } from '../../utilities/log';
|
|
3
|
+
export class ResponseSync extends Response {
|
|
4
|
+
bodyUsed = true;
|
|
5
|
+
#text;
|
|
6
|
+
#json;
|
|
7
|
+
constructor(init) {
|
|
8
|
+
super(...init);
|
|
9
|
+
this.#text = init[0];
|
|
10
|
+
}
|
|
11
|
+
// @ts-expect-error Changing inherited types
|
|
12
|
+
text() {
|
|
13
|
+
return this.#text;
|
|
14
|
+
}
|
|
15
|
+
json() {
|
|
16
|
+
return (this.#json ??= parseJSON(this.#text));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Access response properties at the top level instead.
|
|
20
|
+
*/
|
|
21
|
+
get response() {
|
|
22
|
+
if (__HYDROGEN_DEV__) {
|
|
23
|
+
log.warn(`Property 'response' is deprecated from the result of 'fetchSync'.` +
|
|
24
|
+
` Access response properties at the top level instead.`);
|
|
25
|
+
}
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
static async toSerializable(response) {
|
|
29
|
+
return [
|
|
30
|
+
await response.text(),
|
|
31
|
+
{
|
|
32
|
+
status: response.status,
|
|
33
|
+
statusText: response.statusText,
|
|
34
|
+
headers: Array.from(response.headers.entries()),
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ResponseSync } from '../ResponseSync';
|
|
2
2
|
/**
|
|
3
3
|
* Fetch a URL for use in a client component Suspense boundary.
|
|
4
4
|
*/
|
|
5
|
-
export declare function fetchSync(url: string, options?: RequestInit):
|
|
5
|
+
export declare function fetchSync(url: string, options?: RequestInit): ResponseSync;
|
|
6
6
|
/**
|
|
7
7
|
* Preload a URL for use in a client component Suspense boundary.
|
|
8
8
|
* Useful for placing higher in the tree to avoid waterfalls.
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { parseJSON } from '../../../utilities/parse';
|
|
2
1
|
import { suspendFunction, preloadFunction } from '../../../utilities/suspense';
|
|
2
|
+
import { ResponseSync } from '../ResponseSync';
|
|
3
3
|
/**
|
|
4
4
|
* Fetch a URL for use in a client component Suspense boundary.
|
|
5
5
|
*/
|
|
6
6
|
export function fetchSync(url, options) {
|
|
7
|
-
const
|
|
8
|
-
const response = await globalThis.fetch(url, options);
|
|
9
|
-
|
|
10
|
-
return [text, response];
|
|
7
|
+
const responseSyncInit = suspendFunction([url, options], async () => {
|
|
8
|
+
const response = await globalThis.fetch(new URL(url, window.location.origin), options);
|
|
9
|
+
return ResponseSync.toSerializable(response);
|
|
11
10
|
});
|
|
12
|
-
return
|
|
13
|
-
response,
|
|
14
|
-
json: () => parseJSON(text),
|
|
15
|
-
text: () => text,
|
|
16
|
-
};
|
|
11
|
+
return new ResponseSync(responseSyncInit);
|
|
17
12
|
}
|
|
18
13
|
/**
|
|
19
14
|
* Preload a URL for use in a client component Suspense boundary.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type HydrogenUseQueryOptions } from '../../useQuery/hooks';
|
|
2
|
-
import
|
|
2
|
+
import { ResponseSync } from '../ResponseSync';
|
|
3
3
|
/**
|
|
4
4
|
* The `fetchSync` hook makes API requests and is the recommended way to make simple fetch calls on the server and the client.
|
|
5
5
|
* It's designed similar to the [Web API's `fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch), only in a way
|
|
6
6
|
* that supports [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html).
|
|
7
7
|
*/
|
|
8
|
-
export declare function fetchSync(url: string, options?: Omit<RequestInit, 'cache'> & HydrogenUseQueryOptions):
|
|
8
|
+
export declare function fetchSync(url: string, options?: Omit<RequestInit, 'cache'> & HydrogenUseQueryOptions): ResponseSync;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { parseJSON } from '../../../utilities/parse';
|
|
2
1
|
import { useQuery } from '../../useQuery/hooks';
|
|
2
|
+
import { useUrl } from '../../useUrl';
|
|
3
|
+
import { ResponseSync } from '../ResponseSync';
|
|
3
4
|
/**
|
|
4
5
|
* The `fetchSync` hook makes API requests and is the recommended way to make simple fetch calls on the server and the client.
|
|
5
6
|
* It's designed similar to the [Web API's `fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch), only in a way
|
|
@@ -7,11 +8,12 @@ import { useQuery } from '../../useQuery/hooks';
|
|
|
7
8
|
*/
|
|
8
9
|
export function fetchSync(url, options) {
|
|
9
10
|
const { cache, preload, shouldCacheResponse, ...requestInit } = options ?? {};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
12
|
+
const { origin } = useUrl();
|
|
13
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
14
|
+
const { data, error } = useQuery([url, requestInit], async () => {
|
|
15
|
+
const response = await globalThis.fetch(new URL(url, origin), requestInit);
|
|
16
|
+
return ResponseSync.toSerializable(response);
|
|
15
17
|
}, {
|
|
16
18
|
cache,
|
|
17
19
|
preload,
|
|
@@ -20,10 +22,5 @@ export function fetchSync(url, options) {
|
|
|
20
22
|
if (error) {
|
|
21
23
|
throw error;
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
response,
|
|
26
|
-
json: () => parseJSON(data),
|
|
27
|
-
text: () => data,
|
|
28
|
-
};
|
|
25
|
+
return new ResponseSync(data);
|
|
29
26
|
}
|
|
@@ -1,38 +1,34 @@
|
|
|
1
1
|
export function graphiqlHtml(shop, token, apiVersion) {
|
|
2
|
-
return
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
></script>
|
|
21
|
-
<script>
|
|
22
|
-
const fetcher = GraphiQL.createFetcher({
|
|
23
|
-
url: 'https://${shop}/api/${apiVersion}/graphql.json',
|
|
24
|
-
headers: {
|
|
2
|
+
return `
|
|
3
|
+
<!DOCTYPE html>
|
|
4
|
+
<html>
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset=utf-8/>
|
|
7
|
+
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
|
|
8
|
+
<title>Shopify Storefront API</title>
|
|
9
|
+
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css" />
|
|
10
|
+
<link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png" />
|
|
11
|
+
<script src="//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<script>window.addEventListener('load', function (event) {
|
|
16
|
+
GraphQLPlayground.init(document.getElementById('root'), {
|
|
17
|
+
endpoint:'https://${shop}/api/${apiVersion}/graphql.json',
|
|
18
|
+
settings:{
|
|
19
|
+
'request.globalHeaders': {
|
|
25
20
|
Accept: 'application/json',
|
|
26
21
|
'Content-Type': 'application/graphql',
|
|
27
22
|
'X-Shopify-Storefront-Access-Token': '${token}'
|
|
28
23
|
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
</
|
|
24
|
+
},
|
|
25
|
+
tabs: [{
|
|
26
|
+
endpoint: 'https://${shop}/api/${apiVersion}/graphql.json',
|
|
27
|
+
query: '{ shop { name } }'
|
|
28
|
+
}]
|
|
29
|
+
})
|
|
30
|
+
})</script>
|
|
31
|
+
</body>
|
|
36
32
|
</html>
|
|
37
33
|
`;
|
|
38
34
|
}
|
|
@@ -3,12 +3,16 @@ import { HYDROGEN_DEFAULT_SERVER_ENTRY } from './vite-plugin-hydrogen-middleware
|
|
|
3
3
|
import MagicString from 'magic-string';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import fs from 'fs';
|
|
6
|
+
import fastGlob from 'fast-glob';
|
|
6
7
|
const SSR_BUNDLE_NAME = 'index.js';
|
|
8
|
+
// Keep this in the outer scope to share it
|
|
9
|
+
// across client <> server builds.
|
|
10
|
+
let clientBuildPath;
|
|
7
11
|
export default () => {
|
|
8
12
|
let config;
|
|
9
13
|
let isESM;
|
|
10
14
|
return {
|
|
11
|
-
name: '
|
|
15
|
+
name: 'hydrogen:platform-entry',
|
|
12
16
|
enforce: 'pre',
|
|
13
17
|
configResolved(_config) {
|
|
14
18
|
config = _config;
|
|
@@ -29,18 +33,43 @@ export default () => {
|
|
|
29
33
|
}
|
|
30
34
|
return null;
|
|
31
35
|
},
|
|
32
|
-
transform(code, id) {
|
|
33
|
-
if (
|
|
36
|
+
async transform(code, id, options) {
|
|
37
|
+
if (config.command === 'build' &&
|
|
38
|
+
options?.ssr &&
|
|
39
|
+
/@shopify\/hydrogen\/.+platforms\/virtual\./.test(normalizePath(id))) {
|
|
34
40
|
const ms = new MagicString(code);
|
|
35
|
-
ms.replace('
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
ms.replace('__HYDROGEN_ENTRY__', HYDROGEN_DEFAULT_SERVER_ENTRY);
|
|
42
|
+
if (!clientBuildPath) {
|
|
43
|
+
// Default value
|
|
44
|
+
clientBuildPath = normalizePath(path.resolve(config.root, config.build.outDir, '..', 'client'));
|
|
45
|
+
}
|
|
46
|
+
ms.replace('__HYDROGEN_HTML_TEMPLATE__', normalizePath(path.resolve(clientBuildPath, 'index.html')));
|
|
47
|
+
ms.replace('__HYDROGEN_RELATIVE_CLIENT_BUILD__', normalizePath(path.relative(normalizePath(path.resolve(config.root, config.build.outDir)), clientBuildPath)));
|
|
48
|
+
const files = clientBuildPath
|
|
49
|
+
? (await fastGlob('**/*', {
|
|
50
|
+
cwd: clientBuildPath,
|
|
51
|
+
ignore: ['**/index.html', `**/${config.build.assetsDir}/**`],
|
|
52
|
+
})).map((file) => '/' + file)
|
|
53
|
+
: [];
|
|
54
|
+
ms.replace("\\['__HYDROGEN_ASSETS__'\\]", JSON.stringify(files));
|
|
55
|
+
ms.replace('__HYDROGEN_ASSETS_DIR__', config.build.assetsDir);
|
|
56
|
+
ms.replace('__HYDROGEN_ASSETS_BASE_URL__', (process.env.HYDROGEN_ASSET_BASE_URL || '').replace(/\/$/, ''));
|
|
57
|
+
// Remove the poison pill
|
|
58
|
+
ms.replace('throw', '//');
|
|
38
59
|
return {
|
|
39
60
|
code: ms.toString(),
|
|
40
61
|
map: ms.generateMap({ file: id, source: id }),
|
|
41
62
|
};
|
|
42
63
|
}
|
|
43
64
|
},
|
|
65
|
+
buildEnd(err) {
|
|
66
|
+
if (!err && !config.build.ssr && config.command === 'build') {
|
|
67
|
+
// Save outDir from client build in the outer scope in order
|
|
68
|
+
// to read it during the server build. The CLI runs Vite in
|
|
69
|
+
// the same process so the scope is shared across builds.
|
|
70
|
+
clientBuildPath = normalizePath(path.resolve(config.root, config.build.outDir));
|
|
71
|
+
}
|
|
72
|
+
},
|
|
44
73
|
generateBundle(options, bundle) {
|
|
45
74
|
if (config.build.ssr) {
|
|
46
75
|
const [key, value] = Object.entries(bundle).find(([, value]) => value.type === 'chunk' && value.isEntry);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LocalizationContextValue } from '../../foundation/ShopifyProvider/types';
|
|
2
|
+
import { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export declare function useLocalization(): LocalizationContextValue & {
|
|
3
|
-
locale:
|
|
4
|
+
locale: `${LanguageCode}-${CountryCode}`;
|
|
4
5
|
};
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LocalizationContext, } from '../../components/LocalizationProvider/LocalizationContext.client';
|
|
1
|
+
import { LocalizationContext } from '../../foundation/ShopifyProvider/ShopifyProvider.client';
|
|
3
2
|
import { useEnvContext } from '../../foundation/ssr-interop';
|
|
4
3
|
export function useLocalization() {
|
|
5
4
|
const localization = useEnvContext((req) => req.ctx.localization, LocalizationContext);
|
|
6
5
|
if (localization == null) {
|
|
7
6
|
throw new Error('No Localization Context available');
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
...localization,
|
|
11
|
-
locale: localization.language.isoCode + '-' + localization.country.isoCode,
|
|
12
|
-
}), [localization]);
|
|
13
|
-
return localizationValue;
|
|
8
|
+
return localization;
|
|
14
9
|
}
|
|
@@ -19,7 +19,7 @@ export function getSelectedVariant(variants, choices) {
|
|
|
19
19
|
export function getOptions(variants) {
|
|
20
20
|
const map = variants.reduce((memo, variant) => {
|
|
21
21
|
if (!variant.selectedOptions) {
|
|
22
|
-
throw new Error(`getOptions requires 'variant.selectedOptions`);
|
|
22
|
+
throw new Error(`'getOptions' requires 'variant.selectedOptions'`);
|
|
23
23
|
}
|
|
24
24
|
variant?.selectedOptions?.forEach((opt) => {
|
|
25
25
|
memo[opt?.name ?? ''] = memo[opt?.name ?? ''] || new Set();
|
|
@@ -40,15 +40,17 @@ export function useShopQuery({ query, variables = {}, cache, preload = false, })
|
|
|
40
40
|
let text;
|
|
41
41
|
let data;
|
|
42
42
|
let useQueryError;
|
|
43
|
+
let response = null;
|
|
43
44
|
try {
|
|
44
|
-
|
|
45
|
+
response = fetchSync(url, {
|
|
45
46
|
...requestInit,
|
|
46
47
|
cache,
|
|
47
48
|
preload,
|
|
48
49
|
shouldCacheResponse,
|
|
49
|
-
})
|
|
50
|
+
});
|
|
51
|
+
text = response.text();
|
|
50
52
|
try {
|
|
51
|
-
data =
|
|
53
|
+
data = response.json();
|
|
52
54
|
}
|
|
53
55
|
catch (error) {
|
|
54
56
|
useQueryError = new Error('Unable to parse response:\n' + text);
|
|
@@ -82,15 +84,16 @@ export function useShopQuery({ query, variables = {}, cache, preload = false, })
|
|
|
82
84
|
*/
|
|
83
85
|
if (data?.errors) {
|
|
84
86
|
const errors = Array.isArray(data.errors) ? data.errors : [data.errors];
|
|
87
|
+
const requestId = response?.headers?.get('x-request-id') ?? '';
|
|
85
88
|
for (const error of errors) {
|
|
86
89
|
if (__HYDROGEN_DEV__ && !__HYDROGEN_TEST__) {
|
|
87
|
-
throw new Error(error.message);
|
|
90
|
+
throw new Error(`Storefront API GraphQL Error: ${error.message}.\nRequest id: ${requestId}`);
|
|
88
91
|
}
|
|
89
92
|
else {
|
|
90
|
-
log.error('GraphQL Error', error);
|
|
93
|
+
log.error('Storefront API GraphQL Error', error, 'Storefront API GraphQL request id', requestId);
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
|
-
log.error(`GraphQL
|
|
96
|
+
log.error(`Storefront API GraphQL error count: ${errors.length}`);
|
|
94
97
|
}
|
|
95
98
|
if (__HYDROGEN_DEV__ &&
|
|
96
99
|
(log.options().showUnusedQueryProperties ||
|
package/dist/esnext/index.d.ts
CHANGED
|
@@ -9,10 +9,12 @@ export * from './client';
|
|
|
9
9
|
* The following are exported from this file because they are intended to be available
|
|
10
10
|
* *only* on the server.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
12
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './foundation/ServerPropsProvider';
|
|
13
|
+
export { useShop } from './foundation/useShop';
|
|
14
|
+
export { useUrl } from './foundation/useUrl';
|
|
15
|
+
export { useShopQuery, type UseShopQueryResponse, } from './hooks/useShopQuery/hooks';
|
|
16
|
+
export { useQuery, type HydrogenUseQueryOptions, } from './foundation/useQuery/hooks';
|
|
17
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
16
18
|
export { FileRoutes } from './foundation/FileRoutes/FileRoutes.server';
|
|
17
19
|
export { Route } from './foundation/Route/Route.server';
|
|
18
20
|
export { Router } from './foundation/Router/Router.server';
|
|
@@ -25,7 +27,6 @@ export { useServerAnalytics } from './foundation/Analytics/hook';
|
|
|
25
27
|
export { ShopifyAnalytics } from './foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server';
|
|
26
28
|
export { ShopifyAnalyticsConstants } from './foundation/Analytics/connectors/Shopify/const';
|
|
27
29
|
export { useSession } from './foundation/useSession/useSession';
|
|
28
|
-
export { useLocalization } from './hooks/useLocalization/useLocalization';
|
|
29
30
|
export { Cookie } from './foundation/Cookie/Cookie';
|
|
30
31
|
/**
|
|
31
32
|
* Export server-only CartQuery here instead of `CartProvider.client` to prevent
|
package/dist/esnext/index.js
CHANGED
|
@@ -9,10 +9,12 @@ export * from './client';
|
|
|
9
9
|
* The following are exported from this file because they are intended to be available
|
|
10
10
|
* *only* on the server.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
12
|
+
export { ServerPropsProvider, ServerPropsContext, } from './foundation/ServerPropsProvider';
|
|
13
|
+
export { useShop } from './foundation/useShop';
|
|
14
|
+
export { useUrl } from './foundation/useUrl';
|
|
15
|
+
export { useShopQuery, } from './hooks/useShopQuery/hooks';
|
|
16
|
+
export { useQuery, } from './foundation/useQuery/hooks';
|
|
17
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
16
18
|
export { FileRoutes } from './foundation/FileRoutes/FileRoutes.server';
|
|
17
19
|
export { Route } from './foundation/Route/Route.server';
|
|
18
20
|
export { Router } from './foundation/Router/Router.server';
|
|
@@ -25,7 +27,6 @@ export { useServerAnalytics } from './foundation/Analytics/hook';
|
|
|
25
27
|
export { ShopifyAnalytics } from './foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server';
|
|
26
28
|
export { ShopifyAnalyticsConstants } from './foundation/Analytics/connectors/Shopify/const';
|
|
27
29
|
export { useSession } from './foundation/useSession/useSession';
|
|
28
|
-
export { useLocalization } from './hooks/useLocalization/useLocalization';
|
|
29
30
|
export { Cookie } from './foundation/Cookie/Cookie';
|
|
30
31
|
/**
|
|
31
32
|
* Export server-only CartQuery here instead of `CartProvider.client` to prevent
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './virtual';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './virtual';
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import '../utilities/web-api-polyfill';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
|
|
4
|
-
// eslint-disable-next-line node/no-missing-import
|
|
5
|
-
import entrypoint from '__SERVER_ENTRY__';
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
// eslint-disable-next-line node/no-missing-import
|
|
8
|
-
import indexTemplate from '__INDEX_TEMPLATE__?raw';
|
|
3
|
+
import { handleRequest, indexTemplate, relativeClientBuildPath } from './virtual';
|
|
9
4
|
import { hydrogenMiddleware } from '../framework/middleware';
|
|
10
5
|
// @ts-ignore
|
|
11
6
|
import serveStatic from 'serve-static';
|
|
@@ -14,13 +9,12 @@ import compression from 'compression';
|
|
|
14
9
|
import bodyParser from 'body-parser';
|
|
15
10
|
import connect from 'connect';
|
|
16
11
|
import { InMemoryCache } from '../framework/cache/in-memory';
|
|
17
|
-
const handleRequest = entrypoint;
|
|
18
12
|
export async function createServer({ cache = new InMemoryCache(), } = {}) {
|
|
19
13
|
// @ts-ignore
|
|
20
14
|
globalThis.Oxygen = { env: process.env };
|
|
21
15
|
const app = connect();
|
|
22
16
|
app.use(compression());
|
|
23
|
-
app.use(serveStatic(path.resolve(__dirname,
|
|
17
|
+
app.use(serveStatic(path.resolve(__dirname, relativeClientBuildPath), {
|
|
24
18
|
index: false,
|
|
25
19
|
}));
|
|
26
20
|
app.use(bodyParser.raw({ type: '*/*' }));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RequestHandler } from '../shared-types';
|
|
2
|
+
export declare const handleRequest: RequestHandler;
|
|
3
|
+
export { default as indexTemplate } from '__HYDROGEN_HTML_TEMPLATE__?raw';
|
|
4
|
+
export declare const assets: Set<string>;
|
|
5
|
+
export declare const assetPrefix: string;
|
|
6
|
+
export declare const isAsset: (pathname?: string) => boolean;
|
|
7
|
+
export declare const relativeClientBuildPath: string;
|
|
8
|
+
export declare const assetBasePath: string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// This file is modified by Vite at build time
|
|
2
|
+
// with user project information and re-exports it.
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
// eslint-disable-next-line node/no-missing-import
|
|
5
|
+
import appEntry from '__HYDROGEN_ENTRY__';
|
|
6
|
+
export const handleRequest = appEntry;
|
|
7
|
+
// eslint-disable-next-line node/no-missing-import
|
|
8
|
+
export { default as indexTemplate } from '__HYDROGEN_HTML_TEMPLATE__?raw';
|
|
9
|
+
export const assets = new Set(['__HYDROGEN_ASSETS__']);
|
|
10
|
+
export const assetPrefix = '/__HYDROGEN_ASSETS_DIR__/';
|
|
11
|
+
export const isAsset = (pathname = '') => pathname.startsWith(assetPrefix) || assets.has(pathname);
|
|
12
|
+
export const relativeClientBuildPath = '__HYDROGEN_RELATIVE_CLIENT_BUILD__';
|
|
13
|
+
export const assetBasePath = '__HYDROGEN_ASSETS_BASE_URL__';
|
|
14
|
+
throw new Error('This file must be overwritten in a Vite plugin');
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
// eslint-disable-next-line node/no-missing-import
|
|
3
|
-
import entrypoint from '__SERVER_ENTRY__';
|
|
4
|
-
// @ts-ignore
|
|
5
|
-
// eslint-disable-next-line node/no-missing-import
|
|
6
|
-
import indexTemplate from '__INDEX_TEMPLATE__?raw';
|
|
7
|
-
const handleRequest = entrypoint;
|
|
1
|
+
import { handleRequest, indexTemplate, isAsset, assetBasePath } from './virtual';
|
|
8
2
|
export default {
|
|
9
3
|
async fetch(request, env, context) {
|
|
4
|
+
// Proxy assets to the CDN. This should be removed
|
|
5
|
+
// once the proxy is implemented in Oxygen itself.
|
|
6
|
+
const url = new URL(request.url);
|
|
7
|
+
if (assetBasePath && isAsset(url.pathname)) {
|
|
8
|
+
return fetch(request.url.replace(url.origin, assetBasePath), request);
|
|
9
|
+
}
|
|
10
10
|
if (!globalThis.Oxygen) {
|
|
11
11
|
globalThis.Oxygen = { env };
|
|
12
12
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Image as ImageType } from '../storefront-api-types';
|
|
2
2
|
import type { PartialDeep } from 'type-fest';
|
|
3
3
|
import type { ShopifyLoaderOptions, ShopifyLoaderParams } from '../components/Image';
|
|
4
|
+
export declare const IMG_SRC_SET_SIZES: number[];
|
|
4
5
|
/**
|
|
5
6
|
* Adds image size parameters to an image URL hosted by Shopify's CDN
|
|
6
7
|
*/
|