@shopify/hydrogen 0.26.0 → 0.27.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 +61 -5
- package/dist/esnext/components/Link/Link.client.js +7 -4
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +1 -2
- package/dist/esnext/components/Money/Money.client.d.ts +1 -1
- package/dist/esnext/components/Money/Money.client.js +1 -1
- package/dist/esnext/entry-server.js +19 -6
- package/dist/esnext/foundation/Analytics/ServerAnalyticsRoute.js +31 -16
- package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js +20 -3
- package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/ServerAnalyticsConnector.d.ts +1 -1
- package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/ServerAnalyticsConnector.js +3 -23
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ServerAnalyticsConnector.d.ts +1 -1
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ServerAnalyticsConnector.js +3 -17
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.client.js +4 -12
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server.js +20 -0
- package/dist/esnext/foundation/DevTools/DevTools.server.js +2 -2
- package/dist/esnext/foundation/Router/BrowserRouter.client.d.ts +1 -1
- package/dist/esnext/foundation/Router/BrowserRouter.client.js +7 -5
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +5 -5
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +3 -3
- package/dist/esnext/foundation/constants.d.ts +2 -1
- package/dist/esnext/foundation/constants.js +2 -1
- package/dist/esnext/foundation/useNavigate/useNavigate.js +8 -2
- package/dist/esnext/foundation/useUrl/useUrl.js +5 -3
- package/dist/esnext/framework/load-config.d.ts +0 -1
- package/dist/esnext/framework/load-config.js +1 -4
- package/dist/esnext/framework/plugin.js +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +2 -2
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +2 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.js +2 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-virtual-files.js +4 -21
- package/dist/esnext/framework/types.d.ts +1 -0
- package/dist/esnext/hooks/useMoney/hooks.d.ts +1 -1
- package/dist/esnext/shared-types.d.ts +2 -1
- package/dist/esnext/types.d.ts +1 -1
- package/dist/esnext/utilities/image_size.js +11 -0
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/load-config.d.ts +0 -1
- package/dist/node/framework/load-config.js +1 -4
- package/dist/node/framework/plugin.js +1 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +2 -2
- package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +2 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.js +2 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-virtual-files.js +4 -21
- package/dist/node/framework/types.d.ts +1 -0
- package/dist/node/shared-types.d.ts +2 -1
- package/package.json +1 -1
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +26 -12
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.development.js +18 -3
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.production.min.js +2 -2
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +26 -12
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite.js +18 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.27.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1728](https://github.com/Shopify/hydrogen/pull/1728) [`e8d4980a`](https://github.com/Shopify/hydrogen/commit/e8d4980a691c68e71c56762596a59415f59600c6) Thanks [@jplhomer](https://github.com/jplhomer)! - This is an example of backporting a fix. You can ignore this version.
|
|
8
|
+
|
|
9
|
+
## 0.27.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#1697](https://github.com/Shopify/hydrogen/pull/1697) [`85aab092`](https://github.com/Shopify/hydrogen/commit/85aab092b2f47d77bb917659918a011783cd8c34) Thanks [@blittle](https://github.com/blittle)! - Remove `defaultLocale` from the Hydrogen Config and instead add `defaultCountryCode` and `defaultLanguageCode`. Both of which are also now available by the `useShop()` hook:
|
|
14
|
+
|
|
15
|
+
```diff
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
shopify: {
|
|
18
|
+
- defaultLocale: 'EN-US',
|
|
19
|
+
+ defaultCountryCode: 'US',
|
|
20
|
+
+ defaultLanguageCode: 'EN',
|
|
21
|
+
storeDomain: 'hydrogen-preview.myshopify.com',
|
|
22
|
+
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
|
|
23
|
+
storefrontApiVersion: '2022-07',
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
* [#1662](https://github.com/Shopify/hydrogen/pull/1662) [`4262b319`](https://github.com/Shopify/hydrogen/commit/4262b3196afb96415d3b0f8f874f351030e6a734) Thanks [@wizardlyhel](https://github.com/wizardlyhel)! - Fix server analytics route
|
|
29
|
+
|
|
30
|
+
- Fix ServerAnalyticsRoute so that it does complete all async work
|
|
31
|
+
- Move Performance and Shopify analytic reporting to client side
|
|
32
|
+
- Make sure `ShopifyAnalytics` make its own query for shop id and currency
|
|
33
|
+
- Remove query for shop id and currency from `DefaultSeo` component
|
|
34
|
+
- Make Performance and Shopify server analytics connector do nothing
|
|
35
|
+
|
|
36
|
+
### Deprecated components
|
|
37
|
+
|
|
38
|
+
Remove the following components from `hydrogen.config.js`
|
|
39
|
+
|
|
40
|
+
- `PerformanceMetricsServerAnalyticsConnector`
|
|
41
|
+
- `ShopifyServerAnalyticsConnector`
|
|
42
|
+
|
|
43
|
+
## 0.26.1
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- [#1663](https://github.com/Shopify/hydrogen/pull/1663) [`66200d6b`](https://github.com/Shopify/hydrogen/commit/66200d6b7d8e54b0746a048e950f067d4b8e0609) Thanks [@jplhomer](https://github.com/jplhomer)! - Default to 'US' CountryCode if locale cannot be parsed correctly
|
|
48
|
+
|
|
49
|
+
* [#1690](https://github.com/Shopify/hydrogen/pull/1690) [`afde8989`](https://github.com/Shopify/hydrogen/commit/afde8989ae03e842de65ac698ab86033e56e7ee2) Thanks [@frehner](https://github.com/frehner)! - Add scale to the filename part of the url in `shopifyImageLoader()`
|
|
50
|
+
|
|
51
|
+
- [#1676](https://github.com/Shopify/hydrogen/pull/1676) [`0149cbf6`](https://github.com/Shopify/hydrogen/commit/0149cbf60b331461ae0c97bb3e18d3f27e143d0a) Thanks [@frandiox](https://github.com/frandiox)! - Avoid writing to Node response if it has been closed early.
|
|
52
|
+
|
|
53
|
+
* [#1674](https://github.com/Shopify/hydrogen/pull/1674) [`8068d3ce`](https://github.com/Shopify/hydrogen/commit/8068d3ce14f44ea83bde8f3729ae2a8cbbf8a52e) Thanks [@frandiox](https://github.com/frandiox)! - Throw error when `<Link>` component is used outside of `<Router>` component.
|
|
54
|
+
|
|
55
|
+
- [#1680](https://github.com/Shopify/hydrogen/pull/1680) [`acf5223f`](https://github.com/Shopify/hydrogen/commit/acf5223fe34cfdd483ae9b0e714445c8cbf11a9d) Thanks [@blittle](https://github.com/blittle)! - Fix basepath to not apply to external URLs in the `<Link` component. Also default the attribute `rel="noreferrer noopener` for external URLs.
|
|
56
|
+
|
|
57
|
+
* [#1670](https://github.com/Shopify/hydrogen/pull/1670) [`8b26f7a6`](https://github.com/Shopify/hydrogen/commit/8b26f7a6f034eaa36bb11974ff3dc5d992e2e97b) Thanks [@frandiox](https://github.com/frandiox)! - Optimize client boundaries only during build by default.
|
|
58
|
+
|
|
3
59
|
## 0.26.0
|
|
4
60
|
|
|
5
61
|
### Minor Changes
|
|
@@ -1525,11 +1581,11 @@
|
|
|
1525
1581
|
|
|
1526
1582
|
`queryShop` accepts a single argument object with the following properties:
|
|
1527
1583
|
|
|
1528
|
-
| Property | Type
|
|
1529
|
-
| ----------- |
|
|
1530
|
-
| `query` | `string \| ASTNode`
|
|
1531
|
-
| `variables` | `Record<string, any>`
|
|
1532
|
-
| `locale` | `string
|
|
1584
|
+
| Property | Type | Required |
|
|
1585
|
+
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
1586
|
+
| `query` | `string \| ASTNode` | Yes |
|
|
1587
|
+
| `variables` | `Record<string, any>` | No |
|
|
1588
|
+
| `locale` | `string`. Defaults to the locale value from the [LocalizationProvider](https://shopify.dev/api/hydrogen/components/localization/localizationprovider) component. | No |
|
|
1533
1589
|
|
|
1534
1590
|
**Important**: In order to use `queryShop`, you should pass `shopifyConfig` to `renderHydrogen` inside `App.server.jsx`:
|
|
1535
1591
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useLocation } from '../../foundation/Router/BrowserRouter.client';
|
|
3
3
|
import { createPath } from 'history';
|
|
4
4
|
import { buildPath, useNavigate } from '../../foundation/useNavigate/useNavigate';
|
|
5
5
|
import { RSC_PATHNAME } from '../../constants';
|
|
@@ -12,7 +12,7 @@ import { useBasePath } from '../../foundation/useRouteParams/RouteParamsProvider
|
|
|
12
12
|
*/
|
|
13
13
|
export const Link = React.forwardRef(function Link(props, ref) {
|
|
14
14
|
const navigate = useNavigate();
|
|
15
|
-
const
|
|
15
|
+
const location = useLocation();
|
|
16
16
|
const [_, startTransition] = React.useTransition();
|
|
17
17
|
const routeBasePath = useBasePath();
|
|
18
18
|
/**
|
|
@@ -98,12 +98,15 @@ export const Link = React.forwardRef(function Link(props, ref) {
|
|
|
98
98
|
'reloadDocument',
|
|
99
99
|
'prefetch',
|
|
100
100
|
'scroll',
|
|
101
|
-
]), ref: ref,
|
|
101
|
+
]), ref: ref, rel: props.rel ??
|
|
102
|
+
(to.startsWith('http') || to.startsWith('//')
|
|
103
|
+
? 'noreferrer noopener'
|
|
104
|
+
: undefined), onClick: internalClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onFocus: onFocus, onBlur: onBlur, onTouchStart: onTouchStart, href: to }, props.children),
|
|
102
105
|
shouldPrefetch && React.createElement(Prefetch, { pathname: to })));
|
|
103
106
|
});
|
|
104
107
|
function Prefetch({ pathname }) {
|
|
105
108
|
const { getProposedLocationServerProps } = useInternalServerProps();
|
|
106
|
-
const
|
|
109
|
+
const location = useLocation();
|
|
107
110
|
const newPath = createPath({ pathname });
|
|
108
111
|
if (pathname.startsWith('http') || newPath === createPath(location)) {
|
|
109
112
|
return null;
|
|
@@ -10,8 +10,7 @@ import { useServerRequest } from '../../foundation/ServerRequestProvider';
|
|
|
10
10
|
* Any descendents of this provider can use the `useLocalization` hook.
|
|
11
11
|
*/
|
|
12
12
|
export function LocalizationProvider(props) {
|
|
13
|
-
const {
|
|
14
|
-
const defaultCountryCode = locale.split(/[-_]/)[1] || '';
|
|
13
|
+
const { defaultLanguageCode, defaultCountryCode } = useShop();
|
|
15
14
|
const languageCode = (props.languageCode ?? defaultLanguageCode).toUpperCase();
|
|
16
15
|
const countryCode = (props.countryCode ?? defaultCountryCode).toUpperCase();
|
|
17
16
|
const request = useServerRequest();
|
|
@@ -19,7 +19,7 @@ declare type MoneyProps<ComponentGeneric extends React.ElementType> = CustomProp
|
|
|
19
19
|
/**
|
|
20
20
|
* The `Money` component renders a string of the Storefront API's
|
|
21
21
|
* [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
|
|
22
|
-
* `
|
|
22
|
+
* `locale` in [the `LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).
|
|
23
23
|
*/
|
|
24
24
|
export declare function Money<TTag extends React.ElementType>({ data, as, withoutCurrency, withoutTrailingZeros, measurement, measurementSeparator, ...passthroughProps }: MoneyProps<TTag>): JSX.Element;
|
|
25
25
|
export {};
|
|
@@ -3,7 +3,7 @@ import { useMoney } from '../../hooks';
|
|
|
3
3
|
/**
|
|
4
4
|
* The `Money` component renders a string of the Storefront API's
|
|
5
5
|
* [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
|
|
6
|
-
* `
|
|
6
|
+
* `locale` in [the `LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).
|
|
7
7
|
*/
|
|
8
8
|
export function Money({ data, as, withoutCurrency, withoutTrailingZeros, measurement, measurementSeparator = '/', ...passthroughProps }) {
|
|
9
9
|
if (!isMoney(data)) {
|
|
@@ -337,11 +337,13 @@ async function runSSR({ rsc, state, request, response, nodeResponse, template, n
|
|
|
337
337
|
startWritingToNodeResponse(nodeResponse, dev ? didError() : undefined);
|
|
338
338
|
setTimeout(() => {
|
|
339
339
|
log.trace('node pipe response');
|
|
340
|
-
|
|
340
|
+
if (!nodeResponse.writableEnded)
|
|
341
|
+
pipe(nodeResponse);
|
|
341
342
|
}, 0);
|
|
342
343
|
bufferReadableStream(rscReadable.getReader(), (chunk) => {
|
|
343
344
|
log.trace('rsc chunk');
|
|
344
|
-
|
|
345
|
+
if (!nodeResponse.writableEnded)
|
|
346
|
+
nodeResponse.write(chunk);
|
|
345
347
|
});
|
|
346
348
|
},
|
|
347
349
|
async onAllReady() {
|
|
@@ -370,8 +372,10 @@ async function runSSR({ rsc, state, request, response, nodeResponse, template, n
|
|
|
370
372
|
html = assembleHtml({ ssrHtml, rscPayload, request, template });
|
|
371
373
|
postRequestTasks('ssr', nodeResponse.statusCode, request, response);
|
|
372
374
|
}
|
|
373
|
-
nodeResponse.
|
|
374
|
-
|
|
375
|
+
if (!nodeResponse.writableEnded) {
|
|
376
|
+
nodeResponse.write(html);
|
|
377
|
+
nodeResponse.end();
|
|
378
|
+
}
|
|
375
379
|
});
|
|
376
380
|
pipe(bufferedResponse);
|
|
377
381
|
},
|
|
@@ -385,8 +389,15 @@ async function runSSR({ rsc, state, request, response, nodeResponse, template, n
|
|
|
385
389
|
}
|
|
386
390
|
},
|
|
387
391
|
onError(error) {
|
|
392
|
+
if (error.message?.includes('stream closed early')) {
|
|
393
|
+
// This seems to happen when Fizz is still streaming
|
|
394
|
+
// but nodeResponse has been closed by the browser.
|
|
395
|
+
// This is common in tests and during development
|
|
396
|
+
// due to frequent page refresh.
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
388
399
|
ssrDidError = error;
|
|
389
|
-
if (dev && nodeResponse.headersSent) {
|
|
400
|
+
if (dev && nodeResponse.headersSent && !nodeResponse.writableEnded) {
|
|
390
401
|
// Calling write would flush headers automatically.
|
|
391
402
|
// Delay this error until headers are properly sent.
|
|
392
403
|
nodeResponse.write(getErrorMarkup(error));
|
|
@@ -420,6 +431,8 @@ function runRSC({ App, state, log, request, response }) {
|
|
|
420
431
|
}
|
|
421
432
|
export default renderHydrogen;
|
|
422
433
|
function startWritingToNodeResponse(nodeResponse, error) {
|
|
434
|
+
if (nodeResponse.writableEnded)
|
|
435
|
+
return;
|
|
423
436
|
if (!nodeResponse.headersSent) {
|
|
424
437
|
nodeResponse.setHeader(CONTENT_TYPE, HTML_CONTENT_TYPE);
|
|
425
438
|
nodeResponse.write(DOCTYPE);
|
|
@@ -483,7 +496,7 @@ function postRequestTasks(type, status, request, response) {
|
|
|
483
496
|
function handleFetchResponseInNode(fetchResponsePromise, nodeResponse) {
|
|
484
497
|
if (nodeResponse) {
|
|
485
498
|
fetchResponsePromise.then((response) => {
|
|
486
|
-
if (!response)
|
|
499
|
+
if (!response || nodeResponse.writableEnded)
|
|
487
500
|
return;
|
|
488
501
|
setNodeHeaders(response.headers, nodeResponse);
|
|
489
502
|
nodeResponse.statusCode = response.status;
|
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
import { log } from '../../utilities/log';
|
|
2
|
+
const analyticsDefaultResponse = new Response(null, {
|
|
3
|
+
status: 200,
|
|
4
|
+
});
|
|
2
5
|
export async function ServerAnalyticsRoute(request, { hydrogenConfig }) {
|
|
6
|
+
const serverAnalyticsConnectors = hydrogenConfig.serverAnalyticsConnectors;
|
|
7
|
+
if (!serverAnalyticsConnectors) {
|
|
8
|
+
return analyticsDefaultResponse;
|
|
9
|
+
}
|
|
3
10
|
const requestHeader = request.headers;
|
|
4
11
|
const requestUrl = request.url;
|
|
5
|
-
|
|
12
|
+
let analyticsPromise;
|
|
6
13
|
if (requestHeader.get('Content-Length') === '0') {
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
analyticsPromise = Promise.resolve(true)
|
|
15
|
+
.then(async () => {
|
|
16
|
+
return Promise.all(serverAnalyticsConnectors.map(async (connector) => {
|
|
17
|
+
return await connector.request(requestUrl, requestHeader);
|
|
18
|
+
}));
|
|
19
|
+
})
|
|
20
|
+
.catch((error) => {
|
|
21
|
+
log.warn('Failed to resolve server analytics (no content length): ', error);
|
|
9
22
|
});
|
|
10
23
|
}
|
|
11
24
|
else if (requestHeader.get('Content-Type') === 'application/json') {
|
|
12
|
-
Promise.resolve(request.json())
|
|
25
|
+
analyticsPromise = Promise.resolve(request.json())
|
|
13
26
|
.then((data) => {
|
|
14
|
-
serverAnalyticsConnectors
|
|
15
|
-
connector.request(requestUrl, requestHeader, data, 'json');
|
|
16
|
-
});
|
|
27
|
+
return Promise.all(serverAnalyticsConnectors.map(async (connector) => {
|
|
28
|
+
return await connector.request(requestUrl, requestHeader, data, 'json');
|
|
29
|
+
}));
|
|
17
30
|
})
|
|
18
31
|
.catch((error) => {
|
|
19
|
-
log.warn('Fail to resolve server analytics: ', error);
|
|
32
|
+
log.warn('Fail to resolve server analytics (json): ', error);
|
|
20
33
|
});
|
|
21
34
|
}
|
|
22
35
|
else {
|
|
23
|
-
Promise.resolve(request.text())
|
|
24
|
-
.then((data) => {
|
|
25
|
-
serverAnalyticsConnectors
|
|
26
|
-
connector.request(requestUrl, requestHeader, data, 'text');
|
|
36
|
+
analyticsPromise = Promise.resolve(request.text())
|
|
37
|
+
.then(async (data) => {
|
|
38
|
+
await serverAnalyticsConnectors.forEach(async (connector) => {
|
|
39
|
+
await connector.request(requestUrl, requestHeader, data, 'text');
|
|
27
40
|
});
|
|
41
|
+
return Promise.all(serverAnalyticsConnectors.map(async (connector) => {
|
|
42
|
+
return await connector.request(requestUrl, requestHeader, data, 'text');
|
|
43
|
+
}));
|
|
28
44
|
})
|
|
29
45
|
.catch((error) => {
|
|
30
|
-
log.warn('
|
|
46
|
+
log.warn('Failed to resolve server analytics (text): ', error);
|
|
31
47
|
});
|
|
32
48
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
49
|
+
await analyticsPromise;
|
|
50
|
+
return analyticsDefaultResponse;
|
|
36
51
|
}
|
package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js
CHANGED
|
@@ -15,10 +15,27 @@ export function PerformanceMetrics() {
|
|
|
15
15
|
// Executes only on first mount
|
|
16
16
|
window.BOOMR = window.BOOMR || {};
|
|
17
17
|
window.BOOMR.hydrogenPerformanceEvent = (data) => {
|
|
18
|
+
const initTime = new Date().getTime();
|
|
18
19
|
ClientAnalytics.publish(ClientAnalytics.eventNames.PERFORMANCE, true, data);
|
|
19
|
-
ClientAnalytics.
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const pageData = ClientAnalytics.getPageAnalyticsData();
|
|
21
|
+
const shopId = pageData.shopify.shopId || '';
|
|
22
|
+
fetch('https://monorail-edge.shopifysvc.com/v1/produce', {
|
|
23
|
+
method: 'post',
|
|
24
|
+
headers: {
|
|
25
|
+
'content-type': 'text/plain',
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
schema_id: 'hydrogen_buyer_performance/2.0',
|
|
29
|
+
payload: {
|
|
30
|
+
...data,
|
|
31
|
+
shop_id: shopId.substring(shopId.lastIndexOf('/') + 1) || '',
|
|
32
|
+
},
|
|
33
|
+
metadata: {
|
|
34
|
+
event_created_at_ms: initTime,
|
|
35
|
+
event_sent_at_ms: new Date().getTime(),
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
22
39
|
};
|
|
23
40
|
window.BOOMR.storeDomain = storeDomain;
|
|
24
41
|
function boomerangSaveLoadTime(e) {
|
package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/ServerAnalyticsConnector.js
CHANGED
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
import { log } from '../../../../utilities/log';
|
|
2
2
|
export const PerformanceMetricsServerAnalyticsConnector = {
|
|
3
|
-
request(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const initTime = new Date().getTime();
|
|
7
|
-
fetch('https://monorail-edge.shopifysvc.com/v1/produce', {
|
|
8
|
-
method: 'post',
|
|
9
|
-
headers: {
|
|
10
|
-
'content-type': 'text/plain',
|
|
11
|
-
'x-forwarded-for': requestHeader.get('x-forwarded-for') || '',
|
|
12
|
-
'user-agent': requestHeader.get('user-agent') || '',
|
|
13
|
-
},
|
|
14
|
-
body: JSON.stringify({
|
|
15
|
-
schema_id: 'hydrogen_buyer_performance/2.0',
|
|
16
|
-
payload: data,
|
|
17
|
-
metadata: {
|
|
18
|
-
event_created_at_ms: initTime,
|
|
19
|
-
event_sent_at_ms: new Date().getTime(),
|
|
20
|
-
},
|
|
21
|
-
}),
|
|
22
|
-
}).catch((err) => {
|
|
23
|
-
log.error(err);
|
|
24
|
-
});
|
|
25
|
-
}
|
|
3
|
+
request() {
|
|
4
|
+
log.warn('PerformanceMetricsServerAnalyticsConnector has been removed - please remove its reference from hydrogen.config.js');
|
|
5
|
+
return Promise.resolve();
|
|
26
6
|
},
|
|
27
7
|
};
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
import { log } from '../../../../utilities/log';
|
|
2
2
|
export const ShopifyServerAnalyticsConnector = {
|
|
3
|
-
request(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
data.events.forEach((event) => {
|
|
7
|
-
event.payload.client_ip_address = requestHeader.get('x-forwarded-for');
|
|
8
|
-
event.payload.client_user_agent = requestHeader.get('user-agent');
|
|
9
|
-
});
|
|
10
|
-
fetch('https://monorail-edge.shopifysvc.com/unstable/produce_batch', {
|
|
11
|
-
method: 'post',
|
|
12
|
-
headers: {
|
|
13
|
-
'content-type': 'text/plain',
|
|
14
|
-
},
|
|
15
|
-
body: JSON.stringify(data),
|
|
16
|
-
}).catch((err) => {
|
|
17
|
-
log.error(err);
|
|
18
|
-
});
|
|
19
|
-
}
|
|
3
|
+
request() {
|
|
4
|
+
log.warn('ShopifyServerAnalyticsConnector has been removed - please remove its reference from hydrogen.config.js');
|
|
5
|
+
return Promise.resolve();
|
|
20
6
|
},
|
|
21
7
|
};
|
|
@@ -165,19 +165,8 @@ function sendToServer(data) {
|
|
|
165
165
|
};
|
|
166
166
|
batchedData = [];
|
|
167
167
|
batchedTimeout = null;
|
|
168
|
-
// Send to
|
|
168
|
+
// Send to Shopify
|
|
169
169
|
try {
|
|
170
|
-
fetch('/__event?shopify', {
|
|
171
|
-
method: 'post',
|
|
172
|
-
headers: {
|
|
173
|
-
'cache-control': 'no-cache',
|
|
174
|
-
'Content-Type': 'application/json',
|
|
175
|
-
},
|
|
176
|
-
body: JSON.stringify(batchedDataToBeSent),
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
catch (error) {
|
|
180
|
-
// Fallback to client-side
|
|
181
170
|
fetch('https://monorail-edge.shopifysvc.com/unstable/produce_batch', {
|
|
182
171
|
method: 'post',
|
|
183
172
|
headers: {
|
|
@@ -186,5 +175,8 @@ function sendToServer(data) {
|
|
|
186
175
|
body: JSON.stringify(batchedDataToBeSent),
|
|
187
176
|
});
|
|
188
177
|
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
// Do nothing
|
|
180
|
+
}
|
|
189
181
|
}, BATCH_SENT_TIMEOUT);
|
|
190
182
|
}
|
|
@@ -6,13 +6,23 @@ import { useServerAnalytics } from '../../hook';
|
|
|
6
6
|
import { useShop } from '../../../useShop';
|
|
7
7
|
import { SHOPIFY_S, SHOPIFY_Y } from './const';
|
|
8
8
|
import { ShopifyAnalyticsClient } from './ShopifyAnalytics.client';
|
|
9
|
+
import { useShopQuery } from '../../../../hooks/useShopQuery';
|
|
10
|
+
import { CacheLong } from '../../../Cache/strategies';
|
|
11
|
+
import { gql } from '../../../../utilities/graphql-tag';
|
|
9
12
|
export function ShopifyAnalytics({ cookieDomain }) {
|
|
10
13
|
const { storeDomain } = useShop();
|
|
11
14
|
const request = useServerRequest();
|
|
12
15
|
const cookies = parse(request.headers.get('Cookie') || '');
|
|
13
16
|
const domain = cookieDomain || storeDomain;
|
|
17
|
+
const { data: { shop: { id, paymentSettings: { currencyCode }, }, }, } = useShopQuery({
|
|
18
|
+
query: SHOP_QUERY,
|
|
19
|
+
cache: CacheLong(),
|
|
20
|
+
preload: '*',
|
|
21
|
+
});
|
|
14
22
|
useServerAnalytics({
|
|
15
23
|
shopify: {
|
|
24
|
+
shopId: id,
|
|
25
|
+
currency: currencyCode,
|
|
16
26
|
storefrontId: globalThis.Oxygen?.env?.SHOPIFY_STOREFRONT_ID || '0',
|
|
17
27
|
acceptedLanguage: request.headers.get('Accept-Language')?.replace(/-.*/, '') || 'en',
|
|
18
28
|
isPersistentCookie: !!cookies[SHOPIFY_S] || !!cookies[SHOPIFY_Y],
|
|
@@ -21,3 +31,13 @@ export function ShopifyAnalytics({ cookieDomain }) {
|
|
|
21
31
|
return (React.createElement(AnalyticsErrorBoundary, null,
|
|
22
32
|
React.createElement(ShopifyAnalyticsClient, { cookieDomain: domain })));
|
|
23
33
|
}
|
|
34
|
+
const SHOP_QUERY = gql `
|
|
35
|
+
query shopAnalyticsInfo {
|
|
36
|
+
shop {
|
|
37
|
+
id
|
|
38
|
+
paymentSettings {
|
|
39
|
+
currencyCode
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
@@ -4,9 +4,9 @@ import { useServerRequest } from '../ServerRequestProvider';
|
|
|
4
4
|
export function DevTools() {
|
|
5
5
|
const serverRequest = useServerRequest();
|
|
6
6
|
const { shopifyConfig } = serverRequest.ctx;
|
|
7
|
-
const {
|
|
7
|
+
const { defaultLanguageCode: languageCode, defaultCountryCode: countryCode, storeDomain, storefrontApiVersion, } = shopifyConfig || {};
|
|
8
8
|
const settings = {
|
|
9
|
-
locale
|
|
9
|
+
locale: `${languageCode}-${countryCode}`,
|
|
10
10
|
storeDomain,
|
|
11
11
|
storefrontApiVersion,
|
|
12
12
|
};
|
|
@@ -4,7 +4,7 @@ declare type RouterContextValue = {
|
|
|
4
4
|
history: BrowserHistory;
|
|
5
5
|
location: Location;
|
|
6
6
|
};
|
|
7
|
-
export declare const RouterContext: React.Context<
|
|
7
|
+
export declare const RouterContext: React.Context<RouterContextValue | undefined>;
|
|
8
8
|
export declare const BrowserRouter: FC<{
|
|
9
9
|
history?: BrowserHistory;
|
|
10
10
|
children: ReactNode;
|
|
@@ -2,7 +2,7 @@ import { createBrowserHistory } from 'history';
|
|
|
2
2
|
import React, { createContext, useContext, useMemo, useState, useEffect, useLayoutEffect, useCallback, } from 'react';
|
|
3
3
|
import { META_ENV_SSR } from '../ssr-interop';
|
|
4
4
|
import { useInternalServerProps } from '../useServerProps/use-server-props';
|
|
5
|
-
export const RouterContext = createContext(
|
|
5
|
+
export const RouterContext = createContext(undefined);
|
|
6
6
|
let isFirstLoad = true;
|
|
7
7
|
const positions = {};
|
|
8
8
|
export const BrowserRouter = ({ history: pHistory, children }) => {
|
|
@@ -51,11 +51,13 @@ export const BrowserRouter = ({ history: pHistory, children }) => {
|
|
|
51
51
|
} }, children));
|
|
52
52
|
};
|
|
53
53
|
export function useRouter() {
|
|
54
|
+
if (META_ENV_SSR)
|
|
55
|
+
return { location: {}, history: {} };
|
|
56
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
54
57
|
const router = useContext(RouterContext);
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return router;
|
|
58
|
+
if (router)
|
|
59
|
+
return router;
|
|
60
|
+
throw new Error('Router hooks and <Link> component must be used within a <Router> component');
|
|
59
61
|
}
|
|
60
62
|
export function useLocation() {
|
|
61
63
|
return useRouter().location;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { ShopifyProviderClient } from './ShopifyProvider.client';
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_COUNTRY, DEFAULT_LANGUAGE } from '../constants';
|
|
4
4
|
import { useRequestCacheData, useServerRequest } from '../ServerRequestProvider';
|
|
5
5
|
import { getOxygenVariable } from '../../utilities/storefrontApi';
|
|
6
6
|
import { SHOPIFY_STOREFRONT_ID_VARIABLE } from '../../constants';
|
|
7
7
|
function makeShopifyContext(shopifyConfig) {
|
|
8
|
-
const
|
|
9
|
-
const languageCode =
|
|
8
|
+
const countryCode = shopifyConfig.defaultCountryCode ?? DEFAULT_COUNTRY;
|
|
9
|
+
const languageCode = shopifyConfig.defaultLanguageCode ?? DEFAULT_LANGUAGE;
|
|
10
10
|
const storefrontId = getOxygenVariable(SHOPIFY_STOREFRONT_ID_VARIABLE);
|
|
11
11
|
return {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
defaultCountryCode: countryCode.toUpperCase(),
|
|
13
|
+
defaultLanguageCode: languageCode.toUpperCase(),
|
|
14
14
|
storeDomain: shopifyConfig?.storeDomain?.replace(/^https?:\/\//, ''),
|
|
15
15
|
storefrontToken: shopifyConfig.storefrontToken,
|
|
16
16
|
storefrontApiVersion: shopifyConfig.storefrontApiVersion,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { ShopifyConfigFetcher, ShopifyConfig } from '../../types';
|
|
4
|
-
export interface ShopifyContextValue extends Omit<ShopifyConfig, '
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export interface ShopifyContextValue extends Omit<ShopifyConfig, 'defaultLanguageCode' | 'defaultCountryCode'> {
|
|
5
|
+
defaultLanguageCode: `${LanguageCode}`;
|
|
6
|
+
defaultCountryCode: `${CountryCode}`;
|
|
7
7
|
storefrontId: string | null;
|
|
8
8
|
}
|
|
9
9
|
export declare type ShopifyProviderProps = {
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const DEFAULT_COUNTRY = "US";
|
|
2
|
+
export declare const DEFAULT_LANGUAGE = "EN";
|
|
@@ -22,12 +22,18 @@ export function useNavigate() {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
export function buildPath(basePath, path) {
|
|
25
|
+
if (path.startsWith('http') || path.startsWith('//'))
|
|
26
|
+
return path;
|
|
25
27
|
let builtPath = path;
|
|
26
28
|
if (basePath !== '/') {
|
|
29
|
+
const pathFirstChar = path.charAt(0);
|
|
30
|
+
const basePathLastChar = basePath.charAt(basePath.length - 1);
|
|
27
31
|
builtPath =
|
|
28
|
-
|
|
32
|
+
pathFirstChar === '/' && basePathLastChar === '/'
|
|
29
33
|
? basePath + path.substring(1)
|
|
30
|
-
:
|
|
34
|
+
: basePathLastChar !== '/' && pathFirstChar !== '/'
|
|
35
|
+
? basePath + '/' + path
|
|
36
|
+
: basePath + path;
|
|
31
37
|
}
|
|
32
38
|
return builtPath;
|
|
33
39
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useContext, useMemo } from 'react';
|
|
2
2
|
import { RSC_PATHNAME } from '../../constants';
|
|
3
3
|
import { parseJSON } from '../../utilities/parse';
|
|
4
|
-
import {
|
|
4
|
+
import { RouterContext } from '../Router/BrowserRouter.client';
|
|
5
5
|
import { useEnvContext, META_ENV_SSR } from '../ssr-interop';
|
|
6
6
|
/**
|
|
7
7
|
* The `useUrl` hook retrieves the current URL in a server or client component.
|
|
@@ -20,8 +20,10 @@ export function useUrl() {
|
|
|
20
20
|
/**
|
|
21
21
|
* We return a `URL` object instead of passing through `location` because
|
|
22
22
|
* the URL object contains important info like hostname, etc.
|
|
23
|
+
* Note: do not call `useLocation` directly here to avoid throwing errors
|
|
24
|
+
* when `useUrl` is used outside of a Router component (e.g. in <Seo>).
|
|
23
25
|
*/
|
|
24
|
-
const location =
|
|
26
|
+
const location = useContext(RouterContext); // eslint-disable-line react-hooks/rules-of-hooks
|
|
25
27
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
26
28
|
return useMemo(() => new URL(window.location.href), [location]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
27
29
|
}
|
|
@@ -3,8 +3,5 @@ import { VIRTUAL_PROXY_HYDROGEN_CONFIG_ID } from './plugins/vite-plugin-hydrogen
|
|
|
3
3
|
import { viteception } from './viteception';
|
|
4
4
|
export async function loadConfig(options = { root: process.cwd() }) {
|
|
5
5
|
const { loaded } = await viteception([VIRTUAL_PROXY_HYDROGEN_CONFIG_ID], options);
|
|
6
|
-
return {
|
|
7
|
-
configuration: loaded[0].default,
|
|
8
|
-
configurationPath: loaded[0].configPath,
|
|
9
|
-
};
|
|
6
|
+
return { configuration: loaded[0].default };
|
|
10
7
|
}
|