@shopify/hydrogen 0.11.1-experimental.1 → 0.11.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/CHANGELOG.md +18 -12
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +2 -2
- package/dist/esnext/entry-client.js +9 -6
- package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +8 -1
- package/dist/esnext/foundation/useQuery/hooks.d.ts +7 -4
- package/dist/esnext/foundation/useQuery/hooks.js +4 -3
- package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +4 -1
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/esnext/hooks/useProductOptions/useProductOptions.d.ts +1 -1
- package/dist/esnext/hooks/useProductOptions/useProductOptions.js +8 -8
- package/dist/esnext/types.d.ts +3 -1
- package/dist/esnext/utilities/log/log-query-timeline.d.ts +1 -1
- package/dist/esnext/utilities/log/log-query-timeline.js +4 -3
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +8 -1
- package/dist/node/framework/Hydration/ServerComponentRequest.server.js +4 -1
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/node/types.d.ts +3 -1
- package/dist/node/utilities/log/log-query-timeline.d.ts +1 -1
- package/dist/node/utilities/log/log-query-timeline.js +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 0.11.1
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
5
|
+
### Patch Changes
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- [#770](https://github.com/Shopify/hydrogen/pull/770) [`71e0255`](https://github.com/Shopify/hydrogen/commit/71e0255ea48dc1caa34d2c05a1556cc0ce6d4ce9) Thanks [@mcvinci](https://github.com/mcvinci)! - Hydrogen docs: Framework and global hooks content updates
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
* [#761](https://github.com/Shopify/hydrogen/pull/761) [`1142647`](https://github.com/Shopify/hydrogen/commit/114264716bc8f3027e3e6395d523714adbc92014) Thanks [@frehner](https://github.com/frehner)! - Fix issue with components that take in the `as` prop not validating other props when a component is passed to `as`.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
- [#752](https://github.com/Shopify/hydrogen/pull/752) [`b96179f`](https://github.com/Shopify/hydrogen/commit/b96179fdf960da52332a981e29a742b677826834) Thanks [@jplhomer](https://github.com/jplhomer)! - Ensure ProductSeo knows how to handle `featuredImage = null`
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
- b96179fd: Ensure ProductSeo knows how to handle `featuredImage = null`
|
|
16
|
-
- 2e487b7e: Switch to using Changesets for changelogs.
|
|
17
|
-
- 2d8ab7e2: Hydrogen docs: Preloaded queries and query timing
|
|
13
|
+
* [#774](https://github.com/Shopify/hydrogen/pull/774) [`052f148`](https://github.com/Shopify/hydrogen/commit/052f148e0d33029cdc2540afa5ead32825962f3a) Thanks [@frandiox](https://github.com/frandiox)! - Fix internal url usage in platforms like Vercel, which already provides protocol and host in `request.url`.
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
- [#744](https://github.com/Shopify/hydrogen/pull/744) [`2e487b7`](https://github.com/Shopify/hydrogen/commit/2e487b7e70fe0572538dc2a24b6b6b36ba9fc804) Thanks [@jplhomer](https://github.com/jplhomer)! - Switch to using Changesets for changelogs.
|
|
16
|
+
|
|
17
|
+
* [#775](https://github.com/Shopify/hydrogen/pull/775) [`d5b7ee1`](https://github.com/Shopify/hydrogen/commit/d5b7ee1d8312f64922d1f78afc82ec5ad4a3f457) Thanks [@cartogram](https://github.com/cartogram)! - In cases where the `initialVariantId` is missing on the `<ProductProvider />`, the `selectedVariantId` in the returned `object` from `useProduct()` will now use the first available variant _or_ the first variant (if non are available).
|
|
18
|
+
|
|
19
|
+
- [#773](https://github.com/Shopify/hydrogen/pull/773) [`b6a053e`](https://github.com/Shopify/hydrogen/commit/b6a053e774da443b5692dec51546f5558b3018ad) Thanks [@frandiox](https://github.com/frandiox)! - Fix server bundle name in cases where CSS or images are imported in server components.
|
|
20
|
+
|
|
21
|
+
* [#764](https://github.com/Shopify/hydrogen/pull/764) [`5e55da4`](https://github.com/Shopify/hydrogen/commit/5e55da4090692369ff6a3d57fbc6d29124bdf2e9) Thanks [@wizardlyhel](https://github.com/wizardlyhel)! - Preload queries breaking fetch on Cloudfare [#764](https://github.com/Shopify/hydrogen/pull/764)
|
|
22
|
+
|
|
23
|
+
- [#763](https://github.com/Shopify/hydrogen/pull/763) [`ea2857a`](https://github.com/Shopify/hydrogen/commit/ea2857a515866f37f392bca5da8be1139c055a64) Thanks [@frehner](https://github.com/frehner)! - Client-side apps now have React's `StrictMode` component wrapping the whole app, with an option to disable it. If you do turn it off, it is recommended that you still include the `StrictMode` component at as high of a level as possible in your React tree.
|
|
24
|
+
|
|
25
|
+
See also [React 17's docs](https://reactjs.org/docs/strict-mode.html) on `StrictMode`, and [React 18's updates](https://github.com/reactwg/react-18/discussions/19) to `StrictMode`.
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
* [#747](https://github.com/Shopify/hydrogen/pull/747) [`2d8ab7e`](https://github.com/Shopify/hydrogen/commit/2d8ab7e2a8038ff8b43e6e9398e0bb2da72220a0) Thanks [@mcvinci](https://github.com/mcvinci)! - Hydrogen docs: Preloaded queries and query timing
|
|
22
28
|
|
|
23
29
|
## [0.11.0] - 2022-02-24
|
|
24
30
|
|
|
@@ -6,12 +6,12 @@ import { useProduct } from '../ProductProvider';
|
|
|
6
6
|
* It must be a descendent of the `CartProvider` component.
|
|
7
7
|
*/
|
|
8
8
|
export function AddToCartButton(props) {
|
|
9
|
-
var _a, _b
|
|
9
|
+
var _a, _b;
|
|
10
10
|
const [addingItem, setAddingItem] = useState(false);
|
|
11
11
|
const { variantId: explicitVariantId, quantity = 1, attributes, children, onAdd, accessibleAddingToCartLabel, ...passthroughProps } = props;
|
|
12
12
|
const { status, id, cartCreate, linesAdd } = useCart();
|
|
13
13
|
const product = useProduct();
|
|
14
|
-
const variantId = (
|
|
14
|
+
const variantId = (_b = explicitVariantId !== null && explicitVariantId !== void 0 ? explicitVariantId : (_a = product === null || product === void 0 ? void 0 : product.selectedVariant) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '';
|
|
15
15
|
const disabled = explicitVariantId === null ||
|
|
16
16
|
variantId === '' ||
|
|
17
17
|
(product === null || product === void 0 ? void 0 : product.selectedVariant) === null ||
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import React, { Suspense, useState } from 'react';
|
|
2
|
-
// @ts-
|
|
1
|
+
import React, { Suspense, useState, StrictMode, Fragment, } from 'react';
|
|
2
|
+
// @ts-expect-error hydrateRoot isn't on the TS types yet, but we're using React 18 so it exists
|
|
3
3
|
import { hydrateRoot } from 'react-dom';
|
|
4
4
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
5
5
|
import { useServerResponse } from './framework/Hydration/rsc';
|
|
6
6
|
import { ServerStateProvider } from './client';
|
|
7
7
|
import { Router } from './foundation/Router/Router.client';
|
|
8
|
-
const renderHydrogen = async (ClientWrapper) => {
|
|
8
|
+
const renderHydrogen = async (ClientWrapper, config) => {
|
|
9
9
|
const root = document.getElementById('root');
|
|
10
10
|
if (!root) {
|
|
11
11
|
console.error(`Could not find a root element <div id="root"></div> to render.`);
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
// default to StrictMode on, unless explicitly turned off
|
|
15
|
+
const RootComponent = (config === null || config === void 0 ? void 0 : config.strictMode) !== false ? StrictMode : Fragment;
|
|
16
|
+
hydrateRoot(root, React.createElement(RootComponent, null,
|
|
17
|
+
React.createElement(ErrorBoundary, { FallbackComponent: Error },
|
|
18
|
+
React.createElement(Suspense, { fallback: null },
|
|
19
|
+
React.createElement(Content, { clientWrapper: ClientWrapper })))));
|
|
17
20
|
};
|
|
18
21
|
export default renderHydrogen;
|
|
19
22
|
function Content({ clientWrapper: ClientWrapper = ({ children }) => children, }) {
|
|
@@ -96,7 +96,14 @@ export function preloadRequestCacheData(request, preloadQueries) {
|
|
|
96
96
|
promise = preloadQuery.fetcher().then((r) => {
|
|
97
97
|
data = { data: r };
|
|
98
98
|
collectQueryTimings(request, preloadQuery.key, 'resolved', getTime() - startApiTime);
|
|
99
|
-
}, (e) =>
|
|
99
|
+
}, (e) => {
|
|
100
|
+
// The preload query failed for some reason:
|
|
101
|
+
// On Cloudfare, this happens when a Cache item has expired at max-age
|
|
102
|
+
//
|
|
103
|
+
// We need to remove this entry from cache so that render cycle will retry on its own
|
|
104
|
+
cache.delete(cacheKey);
|
|
105
|
+
collectQueryTimings(request, preloadQuery.key, 'expired', getTime() - startApiTime);
|
|
106
|
+
});
|
|
100
107
|
}
|
|
101
108
|
return promise;
|
|
102
109
|
});
|
|
@@ -11,9 +11,10 @@ export interface HydrogenUseQueryOptions {
|
|
|
11
11
|
preload?: PreloadOptions;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* The `useQuery` hook
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* The `useQuery` hook executes an asynchronous operation like `fetch` in a way that
|
|
15
|
+
* supports [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html). It's based
|
|
16
|
+
* on [react-query](https://react-query.tanstack.com/reference/useQuery). You can use this
|
|
17
|
+
* hook to call any third-party APIs.
|
|
17
18
|
*/
|
|
18
19
|
export declare function useQuery<T>(
|
|
19
20
|
/** A string or array to uniquely identify the current query. */
|
|
@@ -23,7 +24,9 @@ queryFn: () => Promise<T>,
|
|
|
23
24
|
/** The options to manage the cache behavior of the sub-request. */
|
|
24
25
|
queryOptions?: HydrogenUseQueryOptions): {
|
|
25
26
|
data?: undefined;
|
|
26
|
-
error: Response;
|
|
27
|
+
error: Response; /**
|
|
28
|
+
* Attempt to read the query from cache. If it doesn't exist or if it's stale, regenerate it.
|
|
29
|
+
*/
|
|
27
30
|
} | {
|
|
28
31
|
data: T;
|
|
29
32
|
error?: undefined;
|
|
@@ -3,9 +3,10 @@ import { deleteItemFromCache, generateSubRequestCacheControlHeader, getItemFromC
|
|
|
3
3
|
import { runDelayedFunction } from '../../framework/runtime';
|
|
4
4
|
import { useRequestCacheData, useServerRequest } from '../ServerRequestProvider';
|
|
5
5
|
/**
|
|
6
|
-
* The `useQuery` hook
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `useQuery` hook executes an asynchronous operation like `fetch` in a way that
|
|
7
|
+
* supports [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html). It's based
|
|
8
|
+
* on [react-query](https://react-query.tanstack.com/reference/useQuery). You can use this
|
|
9
|
+
* hook to call any third-party APIs.
|
|
9
10
|
*/
|
|
10
11
|
export function useQuery(
|
|
11
12
|
/** A string or array to uniquely identify the current query. */
|
|
@@ -100,7 +100,10 @@ function saveToPreloadAllPreload(query) {
|
|
|
100
100
|
*/
|
|
101
101
|
function getUrlFromNodeRequest(request) {
|
|
102
102
|
var _a;
|
|
103
|
+
const url = (_a = request.originalUrl) !== null && _a !== void 0 ? _a : request.url;
|
|
104
|
+
if (url && !url.startsWith('/'))
|
|
105
|
+
return url;
|
|
103
106
|
// TODO: Find out how to determine https from `request` object without forwarded proto
|
|
104
107
|
const secure = request.headers['x-forwarded-proto'] === 'https';
|
|
105
|
-
return new URL(`${secure ? 'https' : 'http'}://${request.headers.host +
|
|
108
|
+
return new URL(`${secure ? 'https' : 'http'}://${request.headers.host + url}`).toString();
|
|
106
109
|
}
|
|
@@ -43,7 +43,7 @@ export default () => {
|
|
|
43
43
|
},
|
|
44
44
|
generateBundle(options, bundle) {
|
|
45
45
|
if (config.build.ssr) {
|
|
46
|
-
const [
|
|
46
|
+
const [key, value] = Object.entries(bundle).find(([, value]) => value.type === 'chunk' && value.isEntry);
|
|
47
47
|
delete bundle[key];
|
|
48
48
|
value.fileName = SSR_BUNDLE_NAME;
|
|
49
49
|
bundle[SSR_BUNDLE_NAME] = value;
|
|
@@ -4,7 +4,7 @@ import { GraphQLConnection } from '../../types';
|
|
|
4
4
|
* The `useProductOptions` hook returns an object that enables you to keep track of the
|
|
5
5
|
* selected variant and/or selling plan state, as well as callbacks for modifying the state.
|
|
6
6
|
*/
|
|
7
|
-
export declare function useProductOptions({ variants: variantsConnection, sellingPlanGroups: sellingPlanGroupsConnection, initialVariantId, }: {
|
|
7
|
+
export declare function useProductOptions({ variants: variantsConnection, sellingPlanGroups: sellingPlanGroupsConnection, initialVariantId: explicitVariantId, }: {
|
|
8
8
|
/** The product's `VariantConnection`. */
|
|
9
9
|
variants?: GraphQLConnection<Variant>;
|
|
10
10
|
/** The product's `SellingPlanGroups`. */
|
|
@@ -5,18 +5,21 @@ import { getOptions, getSelectedVariant } from './helpers';
|
|
|
5
5
|
* The `useProductOptions` hook returns an object that enables you to keep track of the
|
|
6
6
|
* selected variant and/or selling plan state, as well as callbacks for modifying the state.
|
|
7
7
|
*/
|
|
8
|
-
export function useProductOptions({ variants: variantsConnection, sellingPlanGroups: sellingPlanGroupsConnection, initialVariantId, }) {
|
|
8
|
+
export function useProductOptions({ variants: variantsConnection, sellingPlanGroups: sellingPlanGroupsConnection, initialVariantId: explicitVariantId, }) {
|
|
9
9
|
// The flattened variants
|
|
10
10
|
const variants = useMemo(() => (variantsConnection ? flattenConnection(variantsConnection) : []), [variantsConnection]);
|
|
11
11
|
// All the options available for a product, based on all the variants
|
|
12
12
|
const options = useMemo(() => getOptions(variants), [variants]);
|
|
13
|
+
const initialVariantId = explicitVariantId === null
|
|
14
|
+
? explicitVariantId
|
|
15
|
+
: variants.find((variant) => variant.id === explicitVariantId) ||
|
|
16
|
+
variants.find((variant) => variant.availableForSale) ||
|
|
17
|
+
variants[0];
|
|
13
18
|
/**
|
|
14
19
|
* Track the selectedVariant within the hook. If `initialVariantId`
|
|
15
20
|
* is passed, use that as an initial value.
|
|
16
21
|
*/
|
|
17
|
-
const [selectedVariant, setSelectedVariant] = useState(initialVariantId
|
|
18
|
-
? initialVariantId
|
|
19
|
-
: variants.find((variant) => variant.id === initialVariantId));
|
|
22
|
+
const [selectedVariant, setSelectedVariant] = useState(initialVariantId);
|
|
20
23
|
/**
|
|
21
24
|
* Track the selectedOptions within the hook. If a `initialVariantId`
|
|
22
25
|
* is passed, use that to select initial options.
|
|
@@ -34,10 +37,7 @@ export function useProductOptions({ variants: variantsConnection, sellingPlanGro
|
|
|
34
37
|
* values.
|
|
35
38
|
*/
|
|
36
39
|
useEffect(() => {
|
|
37
|
-
|
|
38
|
-
? initialVariantId
|
|
39
|
-
: variants.find((variant) => variant.id === initialVariantId);
|
|
40
|
-
setSelectedVariant(selectedVariant);
|
|
40
|
+
setSelectedVariant(initialVariantId);
|
|
41
41
|
const selectedOptions = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.selectedOptions)
|
|
42
42
|
? selectedVariant.selectedOptions.reduce((memo, optionSet) => {
|
|
43
43
|
memo[optionSet.name] = optionSet.value;
|
package/dist/esnext/types.d.ts
CHANGED
|
@@ -41,8 +41,10 @@ export declare type ServerHandlerConfig = {
|
|
|
41
41
|
};
|
|
42
42
|
export declare type ClientHandlerConfig = {
|
|
43
43
|
shopifyConfig: ShopifyConfig;
|
|
44
|
+
/** React's StrictMode is on by default for your client side app; if you want to turn it off (not recommended), you can pass `false` */
|
|
45
|
+
strictMode?: boolean;
|
|
44
46
|
};
|
|
45
|
-
export declare type ClientHandler = (App:
|
|
47
|
+
export declare type ClientHandler = (App: React.ElementType, config: ClientHandlerConfig) => Promise<void>;
|
|
46
48
|
export interface GraphQLConnection<T> {
|
|
47
49
|
edges?: {
|
|
48
50
|
node: T;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ServerComponentRequest } from '../../framework/Hydration/ServerComponentRequest.server';
|
|
2
2
|
import { QueryKey } from '../../types';
|
|
3
3
|
import type { RenderType } from './log';
|
|
4
|
-
export declare type TimingType = 'requested' | 'resolved' | 'rendered' | 'preload';
|
|
4
|
+
export declare type TimingType = 'requested' | 'resolved' | 'rendered' | 'preload' | 'expired';
|
|
5
5
|
export declare type QueryTiming = {
|
|
6
6
|
name: string;
|
|
7
7
|
timingType: TimingType;
|
|
@@ -9,6 +9,7 @@ const TIMING_MAPPING = {
|
|
|
9
9
|
rendered: 'Rendered',
|
|
10
10
|
resolved: 'Resolved',
|
|
11
11
|
preload: 'Preload',
|
|
12
|
+
expired: 'Expired',
|
|
12
13
|
};
|
|
13
14
|
export function collectQueryTimings(request, queryKey, timingType, duration) {
|
|
14
15
|
request.ctx.queryTimings.push({
|
|
@@ -31,7 +32,6 @@ export function logQueryTimings(type, request) {
|
|
|
31
32
|
const detectMultipleDataLoad = {};
|
|
32
33
|
let suspenseWaterfallDetectedCount = 0;
|
|
33
34
|
queryList.forEach((query, index) => {
|
|
34
|
-
var _a;
|
|
35
35
|
if (query.timingType === 'requested' || query.timingType === 'preload') {
|
|
36
36
|
detectSuspenseWaterfall[query.name] = true;
|
|
37
37
|
}
|
|
@@ -44,8 +44,9 @@ export function logQueryTimings(type, request) {
|
|
|
44
44
|
: 1;
|
|
45
45
|
}
|
|
46
46
|
const loadColor = query.timingType === 'preload' ? green : color;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const duration = query.duration;
|
|
48
|
+
log.debug(color(`│ ${`${(query.timestamp - requestStartTime).toFixed(2)}ms`.padEnd(10)} ${loadColor(TIMING_MAPPING[query.timingType].padEnd(10))} ${query.name}${query.timingType === 'resolved' || query.timingType === 'expired'
|
|
49
|
+
? ` (Took ${duration === null || duration === void 0 ? void 0 : duration.toFixed(2)}ms)`
|
|
49
50
|
: ''}`));
|
|
50
51
|
// SSR + RSC render path generates 2 `load` and `render` for each query
|
|
51
52
|
// We want to avoid falsely identifying a suspense waterfall near the end
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "0.11.
|
|
1
|
+
export declare const LIB_VERSION = "0.11.1";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '0.11.
|
|
1
|
+
export const LIB_VERSION = '0.11.1';
|
|
@@ -121,7 +121,14 @@ function preloadRequestCacheData(request, preloadQueries) {
|
|
|
121
121
|
promise = preloadQuery.fetcher().then((r) => {
|
|
122
122
|
data = { data: r };
|
|
123
123
|
(0, log_1.collectQueryTimings)(request, preloadQuery.key, 'resolved', (0, timing_1.getTime)() - startApiTime);
|
|
124
|
-
}, (e) =>
|
|
124
|
+
}, (e) => {
|
|
125
|
+
// The preload query failed for some reason:
|
|
126
|
+
// On Cloudfare, this happens when a Cache item has expired at max-age
|
|
127
|
+
//
|
|
128
|
+
// We need to remove this entry from cache so that render cycle will retry on its own
|
|
129
|
+
cache.delete(cacheKey);
|
|
130
|
+
(0, log_1.collectQueryTimings)(request, preloadQuery.key, 'expired', (0, timing_1.getTime)() - startApiTime);
|
|
131
|
+
});
|
|
125
132
|
}
|
|
126
133
|
return promise;
|
|
127
134
|
});
|
|
@@ -104,7 +104,10 @@ function saveToPreloadAllPreload(query) {
|
|
|
104
104
|
*/
|
|
105
105
|
function getUrlFromNodeRequest(request) {
|
|
106
106
|
var _a;
|
|
107
|
+
const url = (_a = request.originalUrl) !== null && _a !== void 0 ? _a : request.url;
|
|
108
|
+
if (url && !url.startsWith('/'))
|
|
109
|
+
return url;
|
|
107
110
|
// TODO: Find out how to determine https from `request` object without forwarded proto
|
|
108
111
|
const secure = request.headers['x-forwarded-proto'] === 'https';
|
|
109
|
-
return new URL(`${secure ? 'https' : 'http'}://${request.headers.host +
|
|
112
|
+
return new URL(`${secure ? 'https' : 'http'}://${request.headers.host + url}`).toString();
|
|
110
113
|
}
|
|
@@ -48,7 +48,7 @@ exports.default = () => {
|
|
|
48
48
|
},
|
|
49
49
|
generateBundle(options, bundle) {
|
|
50
50
|
if (config.build.ssr) {
|
|
51
|
-
const [
|
|
51
|
+
const [key, value] = Object.entries(bundle).find(([, value]) => value.type === 'chunk' && value.isEntry);
|
|
52
52
|
delete bundle[key];
|
|
53
53
|
value.fileName = SSR_BUNDLE_NAME;
|
|
54
54
|
bundle[SSR_BUNDLE_NAME] = value;
|
package/dist/node/types.d.ts
CHANGED
|
@@ -41,8 +41,10 @@ export declare type ServerHandlerConfig = {
|
|
|
41
41
|
};
|
|
42
42
|
export declare type ClientHandlerConfig = {
|
|
43
43
|
shopifyConfig: ShopifyConfig;
|
|
44
|
+
/** React's StrictMode is on by default for your client side app; if you want to turn it off (not recommended), you can pass `false` */
|
|
45
|
+
strictMode?: boolean;
|
|
44
46
|
};
|
|
45
|
-
export declare type ClientHandler = (App:
|
|
47
|
+
export declare type ClientHandler = (App: React.ElementType, config: ClientHandlerConfig) => Promise<void>;
|
|
46
48
|
export interface GraphQLConnection<T> {
|
|
47
49
|
edges?: {
|
|
48
50
|
node: T;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ServerComponentRequest } from '../../framework/Hydration/ServerComponentRequest.server';
|
|
2
2
|
import { QueryKey } from '../../types';
|
|
3
3
|
import type { RenderType } from './log';
|
|
4
|
-
export declare type TimingType = 'requested' | 'resolved' | 'rendered' | 'preload';
|
|
4
|
+
export declare type TimingType = 'requested' | 'resolved' | 'rendered' | 'preload' | 'expired';
|
|
5
5
|
export declare type QueryTiming = {
|
|
6
6
|
name: string;
|
|
7
7
|
timingType: TimingType;
|
|
@@ -12,6 +12,7 @@ const TIMING_MAPPING = {
|
|
|
12
12
|
rendered: 'Rendered',
|
|
13
13
|
resolved: 'Resolved',
|
|
14
14
|
preload: 'Preload',
|
|
15
|
+
expired: 'Expired',
|
|
15
16
|
};
|
|
16
17
|
function collectQueryTimings(request, queryKey, timingType, duration) {
|
|
17
18
|
request.ctx.queryTimings.push({
|
|
@@ -35,7 +36,6 @@ function logQueryTimings(type, request) {
|
|
|
35
36
|
const detectMultipleDataLoad = {};
|
|
36
37
|
let suspenseWaterfallDetectedCount = 0;
|
|
37
38
|
queryList.forEach((query, index) => {
|
|
38
|
-
var _a;
|
|
39
39
|
if (query.timingType === 'requested' || query.timingType === 'preload') {
|
|
40
40
|
detectSuspenseWaterfall[query.name] = true;
|
|
41
41
|
}
|
|
@@ -48,8 +48,9 @@ function logQueryTimings(type, request) {
|
|
|
48
48
|
: 1;
|
|
49
49
|
}
|
|
50
50
|
const loadColor = query.timingType === 'preload' ? kolorist_1.green : color;
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const duration = query.duration;
|
|
52
|
+
log.debug(color(`│ ${`${(query.timestamp - requestStartTime).toFixed(2)}ms`.padEnd(10)} ${loadColor(TIMING_MAPPING[query.timingType].padEnd(10))} ${query.name}${query.timingType === 'resolved' || query.timingType === 'expired'
|
|
53
|
+
? ` (Took ${duration === null || duration === void 0 ? void 0 : duration.toFixed(2)}ms)`
|
|
53
54
|
: ''}`));
|
|
54
55
|
// SSR + RSC render path generates 2 `load` and `render` for each query
|
|
55
56
|
// We want to avoid falsely identifying a suspense waterfall near the end
|