@shopify/hydrogen 1.2.0 → 1.3.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/README.md +1 -1
- package/dist/esnext/components/CartProvider/CartProvider.client.js +6 -0
- package/dist/esnext/components/CartProvider/cart-queries.d.ts +1 -1
- package/dist/esnext/components/CartProvider/cart-queries.js +1 -0
- package/dist/esnext/components/Image/Image.d.ts +1 -1
- package/dist/esnext/components/Image/Image.js +4 -4
- package/dist/esnext/components/Image/index.d.ts +1 -1
- package/dist/esnext/components/index.d.ts +1 -1
- package/dist/esnext/components/index.js +1 -1
- package/dist/esnext/constants.d.ts +1 -0
- package/dist/esnext/constants.js +1 -0
- package/dist/esnext/entry-server.js +10 -3
- package/dist/esnext/experimental.d.ts +1 -0
- package/dist/esnext/experimental.js +1 -0
- package/dist/esnext/foundation/Cache/cache.js +0 -1
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.d.ts +1 -0
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.js +1 -0
- package/dist/esnext/foundation/HydrogenResponse/HydrogenResponse.server.d.ts +0 -2
- package/dist/esnext/foundation/HydrogenResponse/HydrogenResponse.server.js +2 -16
- package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +1 -3
- package/dist/esnext/foundation/session/session-types.d.ts +2 -0
- package/dist/esnext/foundation/session/session.d.ts +3 -0
- package/dist/esnext/foundation/session/session.js +16 -0
- package/dist/esnext/foundation/useQuery/hooks.d.ts +3 -0
- package/dist/esnext/foundation/useQuery/hooks.js +1 -1
- package/dist/esnext/foundation/useSession/useSession.d.ts +1 -0
- package/dist/esnext/foundation/useSession/useSession.js +13 -0
- package/dist/esnext/framework/plugin.js +4 -3
- package/dist/esnext/framework/plugins/vite-plugin-assets-version.d.ts +2 -0
- package/dist/esnext/framework/plugins/vite-plugin-assets-version.js +8 -0
- package/dist/esnext/framework/plugins/vite-plugin-css-rsc.js +0 -5
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.d.ts +2 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +8 -4
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-virtual-files.js +24 -6
- package/dist/esnext/framework/types.d.ts +1 -0
- package/dist/esnext/utilities/apiRoutes.js +11 -1
- package/dist/esnext/utilities/log/utils.js +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/foundation/session/session-types.d.ts +2 -0
- package/dist/node/framework/plugin.js +4 -3
- package/dist/node/framework/plugins/vite-plugin-assets-version.d.ts +2 -0
- package/dist/node/framework/plugins/vite-plugin-assets-version.js +11 -0
- package/dist/node/framework/plugins/vite-plugin-css-rsc.js +0 -5
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.d.ts +2 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +11 -4
- package/dist/node/framework/plugins/vite-plugin-hydrogen-virtual-files.js +24 -6
- package/dist/node/framework/types.d.ts +1 -0
- package/package.json +4 -3
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +5 -4
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +5 -4
- package/dist/esnext/framework/plugins/vite-plugin-purge-query-cache.d.ts +0 -3
- package/dist/esnext/framework/plugins/vite-plugin-purge-query-cache.js +0 -11
- package/dist/node/framework/plugins/vite-plugin-purge-query-cache.d.ts +0 -3
- package/dist/node/framework/plugins/vite-plugin-purge-query-cache.js +0 -16
package/README.md
CHANGED
|
@@ -219,6 +219,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
|
|
|
219
219
|
ClientAnalytics.publish(ClientAnalytics.eventNames.ADD_TO_CART, true, {
|
|
220
220
|
addedCartLines: cart.lines,
|
|
221
221
|
cart: data.cartCreate.cart,
|
|
222
|
+
prevCart: null,
|
|
222
223
|
});
|
|
223
224
|
}
|
|
224
225
|
dispatch({
|
|
@@ -258,6 +259,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
|
|
|
258
259
|
ClientAnalytics.publish(ClientAnalytics.eventNames.ADD_TO_CART, true, {
|
|
259
260
|
addedCartLines: lines,
|
|
260
261
|
cart: data.cartLinesAdd.cart,
|
|
262
|
+
prevCart: state.cart,
|
|
261
263
|
});
|
|
262
264
|
dispatch({
|
|
263
265
|
type: 'resolve',
|
|
@@ -289,6 +291,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
|
|
|
289
291
|
ClientAnalytics.publish(ClientAnalytics.eventNames.REMOVE_FROM_CART, true, {
|
|
290
292
|
removedCartLines: lines,
|
|
291
293
|
cart: data.cartLinesRemove.cart,
|
|
294
|
+
prevCart: state.cart,
|
|
292
295
|
});
|
|
293
296
|
dispatch({
|
|
294
297
|
type: 'resolve',
|
|
@@ -320,6 +323,8 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
|
|
|
320
323
|
ClientAnalytics.publish(ClientAnalytics.eventNames.UPDATE_CART, true, {
|
|
321
324
|
updatedCartLines: lines,
|
|
322
325
|
oldCart: state.cart,
|
|
326
|
+
cart: data.cartLinesUpdate.cart,
|
|
327
|
+
prevCart: state.cart,
|
|
323
328
|
});
|
|
324
329
|
dispatch({
|
|
325
330
|
type: 'resolve',
|
|
@@ -432,6 +437,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
|
|
|
432
437
|
ClientAnalytics.publish(ClientAnalytics.eventNames.DISCOUNT_CODE_UPDATED, true, {
|
|
433
438
|
updatedDiscountCodes: discountCodes,
|
|
434
439
|
cart: data.cartDiscountCodesUpdate.cart,
|
|
440
|
+
prevCart: state.cart,
|
|
435
441
|
});
|
|
436
442
|
dispatch({
|
|
437
443
|
type: 'resolve',
|
|
@@ -7,4 +7,4 @@ export declare const CartBuyerIdentityUpdate: (cartFragment: string) => string;
|
|
|
7
7
|
export declare const CartAttributesUpdate: (cartFragment: string) => string;
|
|
8
8
|
export declare const CartDiscountCodesUpdate: (cartFragment: string) => string;
|
|
9
9
|
export declare const CartQuery: (cartFragment: string) => string;
|
|
10
|
-
export declare const defaultCartFragment = "\nfragment CartFragment on Cart {\n id\n checkoutUrl\n totalQuantity\n buyerIdentity {\n countryCode\n customer {\n id\n email\n firstName\n lastName\n displayName\n }\n email\n phone\n }\n lines(first: $numCartLines) {\n edges {\n node {\n id\n quantity\n attributes {\n key\n value\n }\n cost {\n totalAmount {\n amount\n currencyCode\n }\n compareAtAmountPerQuantity {\n amount\n currencyCode\n }\n }\n merchandise {\n ... on ProductVariant {\n id\n availableForSale\n compareAtPriceV2 {\n ...MoneyFragment\n }\n priceV2 {\n ...MoneyFragment\n }\n requiresShipping\n title\n image {\n ...ImageFragment\n }\n product {\n handle\n title\n }\n selectedOptions {\n name\n value\n }\n }\n }\n }\n }\n }\n cost {\n subtotalAmount {\n ...MoneyFragment\n }\n totalAmount {\n ...MoneyFragment\n }\n totalDutyAmount {\n ...MoneyFragment\n }\n totalTaxAmount {\n ...MoneyFragment\n }\n }\n note\n attributes {\n key\n value\n }\n discountCodes {\n code\n }\n}\n\nfragment MoneyFragment on MoneyV2 {\n currencyCode\n amount\n}\nfragment ImageFragment on Image {\n id\n url\n altText\n width\n height\n}\n";
|
|
10
|
+
export declare const defaultCartFragment = "\nfragment CartFragment on Cart {\n id\n checkoutUrl\n totalQuantity\n buyerIdentity {\n countryCode\n customer {\n id\n email\n firstName\n lastName\n displayName\n }\n email\n phone\n }\n lines(first: $numCartLines) {\n edges {\n node {\n id\n quantity\n attributes {\n key\n value\n }\n cost {\n totalAmount {\n amount\n currencyCode\n }\n compareAtAmountPerQuantity {\n amount\n currencyCode\n }\n }\n merchandise {\n ... on ProductVariant {\n id\n availableForSale\n compareAtPriceV2 {\n ...MoneyFragment\n }\n priceV2 {\n ...MoneyFragment\n }\n requiresShipping\n title\n image {\n ...ImageFragment\n }\n product {\n handle\n title\n id\n }\n selectedOptions {\n name\n value\n }\n }\n }\n }\n }\n }\n cost {\n subtotalAmount {\n ...MoneyFragment\n }\n totalAmount {\n ...MoneyFragment\n }\n totalDutyAmount {\n ...MoneyFragment\n }\n totalTaxAmount {\n ...MoneyFragment\n }\n }\n note\n attributes {\n key\n value\n }\n discountCodes {\n code\n }\n}\n\nfragment MoneyFragment on MoneyV2 {\n currencyCode\n amount\n}\nfragment ImageFragment on Image {\n id\n url\n altText\n width\n height\n}\n";
|
|
@@ -79,7 +79,7 @@ declare type LoaderProps<GenericLoaderOpts> = {
|
|
|
79
79
|
*/
|
|
80
80
|
loaderOptions?: GenericLoaderOpts;
|
|
81
81
|
};
|
|
82
|
-
declare type ExternalImageProps<GenericLoaderOpts> = SetRequired<HtmlImageProps, 'src' | 'width' | 'height' | 'alt'> & {
|
|
82
|
+
export declare type ExternalImageProps<GenericLoaderOpts> = SetRequired<HtmlImageProps, 'src' | 'width' | 'height' | 'alt'> & {
|
|
83
83
|
/** A custom function that generates the image URL. Parameters passed in
|
|
84
84
|
* are either `ShopifyLoaderParams` if using the `data` prop, or the
|
|
85
85
|
* `LoaderOptions` object that you pass to `loaderOptions`.
|
|
@@ -27,7 +27,7 @@ export function Image(props) {
|
|
|
27
27
|
return React.createElement(ExternalImage, { ...props });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoader, loaderOptions, widths, ...rest }) {
|
|
30
|
+
function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoader, loaderOptions, widths, decoding = 'async', ...rest }) {
|
|
31
31
|
if (!data.url) {
|
|
32
32
|
throw new Error(`<Image/>: the 'data' prop requires the 'url' property`);
|
|
33
33
|
}
|
|
@@ -72,10 +72,10 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
72
72
|
loader,
|
|
73
73
|
});
|
|
74
74
|
/* eslint-disable hydrogen/prefer-image-component */
|
|
75
|
-
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width: imgElementWidth ?? undefined, height: imgElementHeight ?? undefined, srcSet: finalSrcset }));
|
|
75
|
+
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width: imgElementWidth ?? undefined, height: imgElementHeight ?? undefined, srcSet: finalSrcset, decoding: decoding }));
|
|
76
76
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
77
77
|
}
|
|
78
|
-
function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths, loading, ...rest }) {
|
|
78
|
+
function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths, loading, decoding = 'async', ...rest }) {
|
|
79
79
|
if (!width || !height) {
|
|
80
80
|
throw new Error(`<Image/>: when 'src' is provided, 'width' and 'height' are required and need to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);
|
|
81
81
|
}
|
|
@@ -112,7 +112,7 @@ function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths,
|
|
|
112
112
|
// @ts-expect-error TS doesn't understand that it could exist
|
|
113
113
|
width: loaderOptions?.width ?? width,
|
|
114
114
|
// @ts-expect-error TS doesn't understand that it could exist
|
|
115
|
-
height: loaderOptions?.height ?? height, alt: alt ?? '', loading: loading ?? 'lazy', srcSet: finalSrcset }));
|
|
115
|
+
height: loaderOptions?.height ?? height, alt: alt ?? '', loading: loading ?? 'lazy', srcSet: finalSrcset, decoding: decoding }));
|
|
116
116
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
117
117
|
}
|
|
118
118
|
function internalImageSrcSet({ src, width, crop, scale, widths, loader, height, }) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Image } from './Image.js';
|
|
2
|
-
export type { ShopifyLoaderParams, ShopifyLoaderOptions, ShopifyImageProps, } from './Image.js';
|
|
2
|
+
export type { ShopifyLoaderParams, ShopifyLoaderOptions, ShopifyImageProps, ExternalImageProps, } from './Image.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Link } from './Link/index.js';
|
|
2
2
|
export { MediaFile } from './MediaFile/index.js';
|
|
3
3
|
export { Video } from './Video/index.js';
|
|
4
|
-
export { Image } from './Image/index.js';
|
|
4
|
+
export { Image, type ExternalImageProps, type ShopifyImageProps, } from './Image/index.js';
|
|
5
5
|
export { ExternalVideo } from './ExternalVideo/index.js';
|
|
6
6
|
export { AddToCartButton } from './AddToCartButton/index.js';
|
|
7
7
|
export { ModelViewer } from './ModelViewer/index.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Link } from './Link/index.js';
|
|
2
2
|
export { MediaFile } from './MediaFile/index.js';
|
|
3
3
|
export { Video } from './Video/index.js';
|
|
4
|
-
export { Image } from './Image/index.js';
|
|
4
|
+
export { Image, } from './Image/index.js';
|
|
5
5
|
export { ExternalVideo } from './ExternalVideo/index.js';
|
|
6
6
|
export { AddToCartButton } from './AddToCartButton/index.js';
|
|
7
7
|
export { ModelViewer } from './ModelViewer/index.js';
|
|
@@ -4,6 +4,7 @@ export declare const EVENT_PATHNAME_REGEX: RegExp;
|
|
|
4
4
|
export declare const OXYGEN_SECRET_TOKEN_ENVIRONMENT_VARIABLE = "SHOPIFY_STOREFRONT_API_SECRET_TOKEN";
|
|
5
5
|
export declare const STOREFRONT_API_SECRET_TOKEN_HEADER = "Shopify-Storefront-Private-Token";
|
|
6
6
|
export declare const STOREFRONT_API_PUBLIC_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
|
|
7
|
+
export declare const FORM_REDIRECT_COOKIE = "Hydrogen-Redirect";
|
|
7
8
|
export declare const STOREFRONT_API_BUYER_IP_HEADER = "Shopify-Storefront-Buyer-IP";
|
|
8
9
|
export declare const SHOPIFY_STOREFRONT_ID_VARIABLE = "SHOPIFY_STOREFRONT_ID";
|
|
9
10
|
export declare const SHOPIFY_STOREFRONT_ID_HEADER = "Shopify-Storefront-Id";
|
package/dist/esnext/constants.js
CHANGED
|
@@ -4,6 +4,7 @@ export const EVENT_PATHNAME_REGEX = new RegExp(`^${EVENT_PATHNAME}/`);
|
|
|
4
4
|
export const OXYGEN_SECRET_TOKEN_ENVIRONMENT_VARIABLE = 'SHOPIFY_STOREFRONT_API_SECRET_TOKEN';
|
|
5
5
|
export const STOREFRONT_API_SECRET_TOKEN_HEADER = 'Shopify-Storefront-Private-Token';
|
|
6
6
|
export const STOREFRONT_API_PUBLIC_TOKEN_HEADER = 'X-Shopify-Storefront-Access-Token';
|
|
7
|
+
export const FORM_REDIRECT_COOKIE = 'Hydrogen-Redirect';
|
|
7
8
|
export const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';
|
|
8
9
|
export const SHOPIFY_STOREFRONT_ID_VARIABLE = 'SHOPIFY_STOREFRONT_ID';
|
|
9
10
|
export const SHOPIFY_STOREFRONT_ID_HEADER = 'Shopify-Storefront-Id';
|
|
@@ -20,6 +20,7 @@ import { splitCookiesString } from 'set-cookie-parser';
|
|
|
20
20
|
import { deleteItemFromCache, getItemFromCache, isStale, setItemInCache, } from './foundation/Cache/cache.js';
|
|
21
21
|
import { CacheShort, NO_STORE } from './foundation/Cache/strategies/index.js';
|
|
22
22
|
import { getBuiltInRoute } from './foundation/BuiltInRoutes/BuiltInRoutes.js';
|
|
23
|
+
import { FORM_REDIRECT_COOKIE } from './constants.js';
|
|
23
24
|
const DOCTYPE = '<!DOCTYPE html>';
|
|
24
25
|
const CONTENT_TYPE = 'Content-Type';
|
|
25
26
|
const HTML_CONTENT_TYPE = 'text/html; charset=UTF-8';
|
|
@@ -29,9 +30,10 @@ export const renderHydrogen = (App) => {
|
|
|
29
30
|
const request = new HydrogenRequest(rawRequest);
|
|
30
31
|
const url = new URL(request.url);
|
|
31
32
|
let sessionApi = options.sessionApi;
|
|
32
|
-
const { default:
|
|
33
|
+
const { default: importedConfig } = await import(
|
|
33
34
|
// @ts-ignore
|
|
34
35
|
'virtual__hydrogen.config.ts');
|
|
36
|
+
const inlineHydrogenConfig = typeof importedConfig === 'function' ? importedConfig() : importedConfig;
|
|
35
37
|
const { default: hydrogenRoutes } = await import(
|
|
36
38
|
// @ts-ignore
|
|
37
39
|
'virtual__hydrogen-routes.server.jsx');
|
|
@@ -46,6 +48,10 @@ export const renderHydrogen = (App) => {
|
|
|
46
48
|
const response = new HydrogenResponse(null, {
|
|
47
49
|
headers: headers || {},
|
|
48
50
|
});
|
|
51
|
+
if (request.cookies.get(FORM_REDIRECT_COOKIE)) {
|
|
52
|
+
response.headers.set('SET-COOKIE', `${FORM_REDIRECT_COOKIE}=`);
|
|
53
|
+
response.doNotStream();
|
|
54
|
+
}
|
|
49
55
|
if (hydrogenConfig.poweredByHeader ?? true) {
|
|
50
56
|
// If undefined in the config, then always show the header
|
|
51
57
|
response.headers.set('powered-by', 'Shopify-Hydrogen');
|
|
@@ -97,7 +103,7 @@ export const renderHydrogen = (App) => {
|
|
|
97
103
|
}
|
|
98
104
|
});
|
|
99
105
|
// Asynchronously wait for it in workers
|
|
100
|
-
request.ctx.runtime?.waitUntil(staleWhileRevalidatePromise);
|
|
106
|
+
request.ctx.runtime?.waitUntil?.(staleWhileRevalidatePromise);
|
|
101
107
|
}
|
|
102
108
|
return cachedResponse;
|
|
103
109
|
}
|
|
@@ -137,6 +143,7 @@ async function processRequest(handleRequest, App, url, request, sessionApi, opti
|
|
|
137
143
|
if (isRSCRequest) {
|
|
138
144
|
const buffered = await bufferReadableStream(rsc.readable.getReader());
|
|
139
145
|
postRequestTasks('rsc', 200, request, response);
|
|
146
|
+
response.headers.set('cache-control', response.cacheControlHeader);
|
|
140
147
|
cacheResponse(response, request, [buffered], revalidate);
|
|
141
148
|
return new Response(buffered, {
|
|
142
149
|
headers: response.headers,
|
|
@@ -593,7 +600,7 @@ async function cacheResponse(response, request, chunks, revalidate) {
|
|
|
593
600
|
}
|
|
594
601
|
else {
|
|
595
602
|
const cachePutPromise = Promise.resolve(true).then(() => saveCacheResponse(response, request, chunks));
|
|
596
|
-
request.ctx.runtime?.waitUntil(cachePutPromise);
|
|
603
|
+
request.ctx.runtime?.waitUntil?.(cachePutPromise);
|
|
597
604
|
}
|
|
598
605
|
}
|
|
599
606
|
}
|
|
@@ -88,7 +88,6 @@ export async function setItemInCache(request, response, userCacheOptions) {
|
|
|
88
88
|
const cacheControlString = generateDefaultCacheControlHeader(getCacheControlSetting(cacheControl));
|
|
89
89
|
// CF will override cache-control, so we need to keep a
|
|
90
90
|
// non-modified real-cache-control
|
|
91
|
-
response.headers.set('cache-control', cacheControlString);
|
|
92
91
|
response.headers.set('real-cache-control', cacheControlString);
|
|
93
92
|
response.headers.set('cache-put-date', new Date().toUTCString());
|
|
94
93
|
logCacheApiStatus('PUT', request.url);
|
|
@@ -46,6 +46,7 @@ export declare class HydrogenRequest extends Request {
|
|
|
46
46
|
router: RouterContextData;
|
|
47
47
|
buyerIpHeader?: string;
|
|
48
48
|
session?: SessionSyncApi;
|
|
49
|
+
flashSession: Record<string, any>;
|
|
49
50
|
runtime?: RuntimeContext;
|
|
50
51
|
scopes: Map<string, Record<string, any>>;
|
|
51
52
|
localization?: LocalizationContextValue;
|
|
@@ -3,10 +3,8 @@ import React from 'react';
|
|
|
3
3
|
export declare class HydrogenResponse extends Response {
|
|
4
4
|
private wait;
|
|
5
5
|
private cacheOptions;
|
|
6
|
-
private proxy;
|
|
7
6
|
status: number;
|
|
8
7
|
statusText: string;
|
|
9
|
-
constructor(...args: ConstructorParameters<typeof Response>);
|
|
10
8
|
/**
|
|
11
9
|
* Buffer the current response until all queries have resolved,
|
|
12
10
|
* and prevent it from streaming back early.
|
|
@@ -4,22 +4,8 @@ import React from 'react';
|
|
|
4
4
|
export class HydrogenResponse extends Response {
|
|
5
5
|
wait = false;
|
|
6
6
|
cacheOptions = CacheShort();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
status: { value: 200, writable: true },
|
|
10
|
-
statusText: { value: '', writable: true },
|
|
11
|
-
});
|
|
12
|
-
// @ts-ignore
|
|
13
|
-
status;
|
|
14
|
-
// @ts-ignore
|
|
15
|
-
statusText;
|
|
16
|
-
constructor(...args) {
|
|
17
|
-
super(...args);
|
|
18
|
-
return new Proxy(this, {
|
|
19
|
-
get: (target, key) => target.proxy[key] ?? Reflect.get(target, key),
|
|
20
|
-
set: (target, key, value) => Reflect.set(key in target.proxy ? target.proxy : target, key, value),
|
|
21
|
-
});
|
|
22
|
-
}
|
|
7
|
+
status = 200;
|
|
8
|
+
statusText = '';
|
|
23
9
|
/**
|
|
24
10
|
* Buffer the current response until all queries have resolved,
|
|
25
11
|
* and prevent it from streaming back early.
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useMemo, useCallback,
|
|
2
|
-
// @ts-ignore
|
|
3
|
-
useTransition, useState, } from 'react';
|
|
1
|
+
import React, { createContext, useMemo, useCallback, useTransition, useState, } from 'react';
|
|
4
2
|
const PRIVATE_PROPS = ['request', 'response'];
|
|
5
3
|
export const ServerPropsContext = createContext(null);
|
|
6
4
|
export function ServerPropsProvider({ initialServerProps, setServerPropsForRsc, setRscResponseFromApiRoute, children, }) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export declare type SessionSyncApi = {
|
|
2
2
|
get: () => Record<string, string>;
|
|
3
|
+
set: (data: Record<string, any>) => any;
|
|
3
4
|
};
|
|
4
5
|
export declare type SessionApi = {
|
|
5
6
|
get: () => Promise<Record<string, string>>;
|
|
6
7
|
set: (key: string, value: string) => Promise<void>;
|
|
7
8
|
destroy: () => Promise<void>;
|
|
9
|
+
getFlash: (key: string) => any;
|
|
8
10
|
};
|
|
9
11
|
export declare type SessionStorageAdapter = {
|
|
10
12
|
get: (request: Request) => Promise<Record<string, string>>;
|
|
@@ -4,12 +4,15 @@ import type { HydrogenRequest } from '../HydrogenRequest/HydrogenRequest.server.
|
|
|
4
4
|
import type { SessionStorageAdapter } from './session-types.js';
|
|
5
5
|
export declare function getSyncSessionApi(request: HydrogenRequest, componentResponse: HydrogenResponse, log: Logger, session?: SessionStorageAdapter): {
|
|
6
6
|
get(): any;
|
|
7
|
+
set(data: Record<string, any>): any;
|
|
7
8
|
};
|
|
8
9
|
export declare const emptySessionImplementation: (log: Logger) => {
|
|
10
|
+
getFlash(key: string): Promise<null>;
|
|
9
11
|
get(): Promise<{}>;
|
|
10
12
|
set(key: string, value: string): Promise<void>;
|
|
11
13
|
destroy(): Promise<void>;
|
|
12
14
|
};
|
|
13
15
|
export declare const emptySyncSessionImplementation: (log: Logger) => {
|
|
14
16
|
get(): {};
|
|
17
|
+
set(data: Record<string, any>): null;
|
|
15
18
|
};
|
|
@@ -9,11 +9,23 @@ export function getSyncSessionApi(request, componentResponse, log, session) {
|
|
|
9
9
|
}
|
|
10
10
|
return sessionPromises.getPromise.read();
|
|
11
11
|
},
|
|
12
|
+
set(data) {
|
|
13
|
+
if (!sessionPromises.setPromise) {
|
|
14
|
+
sessionPromises.setPromise = wrapPromise(session.set(request, data));
|
|
15
|
+
}
|
|
16
|
+
const cookie = sessionPromises.setPromise.read();
|
|
17
|
+
componentResponse.headers.set('Set-Cookie', cookie);
|
|
18
|
+
return cookie;
|
|
19
|
+
},
|
|
12
20
|
}
|
|
13
21
|
: emptySyncSessionImplementation(log);
|
|
14
22
|
}
|
|
15
23
|
export const emptySessionImplementation = function (log) {
|
|
16
24
|
return {
|
|
25
|
+
async getFlash(key) {
|
|
26
|
+
log.warn('No session adapter has been configured!');
|
|
27
|
+
return null;
|
|
28
|
+
},
|
|
17
29
|
async get() {
|
|
18
30
|
log.warn('No session adapter has been configured!');
|
|
19
31
|
return {};
|
|
@@ -33,5 +45,9 @@ export const emptySyncSessionImplementation = function (log) {
|
|
|
33
45
|
log.warn('No session adapter has been configured!');
|
|
34
46
|
return {};
|
|
35
47
|
},
|
|
48
|
+
set(data) {
|
|
49
|
+
log.warn('No session adapter has been configured!');
|
|
50
|
+
return null;
|
|
51
|
+
},
|
|
36
52
|
};
|
|
37
53
|
};
|
|
@@ -13,6 +13,9 @@ export interface HydrogenUseQueryOptions {
|
|
|
13
13
|
*/
|
|
14
14
|
shouldCacheResponse?: (body: any) => boolean;
|
|
15
15
|
}
|
|
16
|
+
declare global {
|
|
17
|
+
var __HYDROGEN_CACHE_ID__: string;
|
|
18
|
+
}
|
|
16
19
|
/**
|
|
17
20
|
* The `useQuery` hook executes an asynchronous operation like `fetch` in a way that
|
|
18
21
|
* supports [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html). You can use this
|
|
@@ -19,7 +19,7 @@ queryFn,
|
|
|
19
19
|
queryOptions) {
|
|
20
20
|
const request = useServerRequest();
|
|
21
21
|
const withCacheIdKey = [
|
|
22
|
-
|
|
22
|
+
__HYDROGEN_CACHE_ID__,
|
|
23
23
|
...(typeof key === 'string' ? [key] : key),
|
|
24
24
|
];
|
|
25
25
|
const fetcher = cachedQueryFnBuilder(withCacheIdKey, queryFn, queryOptions);
|
|
@@ -5,3 +5,16 @@ export const useSession = function () {
|
|
|
5
5
|
const session = request.ctx.session?.get() || {};
|
|
6
6
|
return session;
|
|
7
7
|
};
|
|
8
|
+
export const useFlashSession = function (key) {
|
|
9
|
+
const request = useServerRequest();
|
|
10
|
+
const data = request.ctx.session?.get() || {};
|
|
11
|
+
let value = data[key];
|
|
12
|
+
if (value) {
|
|
13
|
+
delete data[key];
|
|
14
|
+
request.ctx.flashSession[key] = value;
|
|
15
|
+
}
|
|
16
|
+
request.ctx.session?.set(data);
|
|
17
|
+
value = request.ctx.flashSession[key];
|
|
18
|
+
delete request.ctx.flashSession[key];
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
@@ -5,7 +5,6 @@ import hydrogenVirtualFiles from './plugins/vite-plugin-hydrogen-virtual-files.j
|
|
|
5
5
|
import platformEntry from './plugins/vite-plugin-platform-entry.js';
|
|
6
6
|
import rsc from './plugins/vite-plugin-hydrogen-rsc.js';
|
|
7
7
|
import ssrInterop from './plugins/vite-plugin-ssr-interop.js';
|
|
8
|
-
import purgeQueryCache from './plugins/vite-plugin-purge-query-cache.js';
|
|
9
8
|
import hydrationAutoImport from './plugins/vite-plugin-hydration-auto-import.js';
|
|
10
9
|
import inspect from 'vite-plugin-inspect';
|
|
11
10
|
import react from '@vitejs/plugin-react';
|
|
@@ -13,10 +12,11 @@ import cssRsc from './plugins/vite-plugin-css-rsc.js';
|
|
|
13
12
|
import cssModulesRsc from './plugins/vite-plugin-css-modules-rsc.js';
|
|
14
13
|
import clientImports from './plugins/vite-plugin-client-imports.js';
|
|
15
14
|
import suppressWarnings from './plugins/vite-plugin-hydrogen-suppress-warnings.js';
|
|
15
|
+
import assetsVersion from './plugins/vite-plugin-assets-version.js';
|
|
16
16
|
const hydrogenPlugin = (pluginOptions = {}) => {
|
|
17
17
|
return [
|
|
18
18
|
process.env.VITE_INSPECT && inspect(),
|
|
19
|
-
hydrogenConfig(),
|
|
19
|
+
hydrogenConfig(pluginOptions),
|
|
20
20
|
hydrogenClientMiddleware(),
|
|
21
21
|
clientImports(),
|
|
22
22
|
hydrogenMiddleware(pluginOptions),
|
|
@@ -28,7 +28,8 @@ const hydrogenPlugin = (pluginOptions = {}) => {
|
|
|
28
28
|
rsc(pluginOptions),
|
|
29
29
|
platformEntry(),
|
|
30
30
|
suppressWarnings(),
|
|
31
|
-
pluginOptions.
|
|
31
|
+
pluginOptions.assetHashVersion &&
|
|
32
|
+
assetsVersion(pluginOptions.assetHashVersion),
|
|
32
33
|
];
|
|
33
34
|
};
|
|
34
35
|
export default hydrogenPlugin; // For ESM
|
|
@@ -35,7 +35,6 @@ export default function cssRsc() {
|
|
|
35
35
|
if (server) {
|
|
36
36
|
const tags = [];
|
|
37
37
|
const foundCssFiles = new Set();
|
|
38
|
-
const { browserHash = '' } = server._optimizedDeps?.metadata || {};
|
|
39
38
|
for (const [key, value] of server.moduleGraph.idToModuleMap.entries()) {
|
|
40
39
|
if (
|
|
41
40
|
// Note: Some CSS-in-JS libraries use `.css.js`
|
|
@@ -55,10 +54,6 @@ export default function cssRsc() {
|
|
|
55
54
|
? url.replace('?', timestampQuery + '&')
|
|
56
55
|
: url + timestampQuery;
|
|
57
56
|
}
|
|
58
|
-
if (browserHash && !url.includes('v=')) {
|
|
59
|
-
// Append the hash at the end
|
|
60
|
-
url += (url.includes('?') ? '&' : '?') + `v=${browserHash}`;
|
|
61
|
-
}
|
|
62
57
|
tags.push(value.type === 'css'
|
|
63
58
|
? { tag: 'link', attrs: { rel: 'stylesheet', href: url } }
|
|
64
59
|
: { tag: 'script', attrs: { type: 'module', src: url } });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import Crypto from 'crypto';
|
|
2
|
+
export default (pluginOptions) => {
|
|
2
3
|
const rollupOptions = {
|
|
3
4
|
output: {},
|
|
4
5
|
};
|
|
@@ -23,7 +24,7 @@ export default () => {
|
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
return {
|
|
26
|
-
name: '
|
|
27
|
+
name: 'hydrogen:config',
|
|
27
28
|
config: async (config, env) => ({
|
|
28
29
|
resolve: {
|
|
29
30
|
alias: {
|
|
@@ -48,7 +49,7 @@ export default () => {
|
|
|
48
49
|
* Tell Vite to bundle everything when we're building for Workers.
|
|
49
50
|
* Otherwise, bundle RSC plugin as a workaround to apply the vendor alias above.
|
|
50
51
|
*/
|
|
51
|
-
noExternal: isWorker || [/react-server-dom-vite/],
|
|
52
|
+
noExternal: isWorker || [/react-server-dom-vite/, /@shopify\/hydrogen/],
|
|
52
53
|
target: isWorker ? 'webworker' : 'node',
|
|
53
54
|
},
|
|
54
55
|
// Reload when updating local Hydrogen lib
|
|
@@ -93,7 +94,10 @@ export default () => {
|
|
|
93
94
|
define: {
|
|
94
95
|
__HYDROGEN_DEV__: env.mode !== 'production',
|
|
95
96
|
__HYDROGEN_WORKER__: isWorker,
|
|
96
|
-
__HYDROGEN_TEST__: false,
|
|
97
|
+
__HYDROGEN_TEST__: false,
|
|
98
|
+
__HYDROGEN_CACHE_ID__: pluginOptions.purgeQueryCacheOnBuild
|
|
99
|
+
? `"${Crypto.randomBytes(8).toString('hex').slice(0, 8)}"`
|
|
100
|
+
: '"__QUERY_CACHE_ID__"',
|
|
97
101
|
},
|
|
98
102
|
envPrefix: ['VITE_', 'PUBLIC_'],
|
|
99
103
|
base: process.env.HYDROGEN_ASSET_BASE_URL,
|
|
@@ -2,6 +2,7 @@ import { normalizePath } from 'vite';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { promises as fs } from 'fs';
|
|
4
4
|
import { viteception } from '../viteception.js';
|
|
5
|
+
import MagicString from 'magic-string';
|
|
5
6
|
export const HYDROGEN_DEFAULT_SERVER_ENTRY = process.env.HYDROGEN_SERVER_ENTRY || '/src/App.server';
|
|
6
7
|
// The character ":" breaks Vite with Node >= 16.15. Use "_" instead
|
|
7
8
|
const VIRTUAL_PREFIX = 'virtual__';
|
|
@@ -17,6 +18,7 @@ export const VIRTUAL_PROXY_HYDROGEN_ROUTES_ID = VIRTUAL_PREFIX + PROXY_PREFIX +
|
|
|
17
18
|
export default (pluginOptions) => {
|
|
18
19
|
let config;
|
|
19
20
|
let server;
|
|
21
|
+
let resolvedConfigPath;
|
|
20
22
|
return {
|
|
21
23
|
name: 'hydrogen:virtual-files',
|
|
22
24
|
configResolved(_config) {
|
|
@@ -27,10 +29,12 @@ export default (pluginOptions) => {
|
|
|
27
29
|
},
|
|
28
30
|
resolveId(source, importer) {
|
|
29
31
|
if (source === VIRTUAL_HYDROGEN_CONFIG_ID) {
|
|
30
|
-
return findHydrogenConfigPath(config.root, pluginOptions.configPath).then((hcPath) =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
return findHydrogenConfigPath(config.root, pluginOptions.configPath).then((hcPath) => {
|
|
33
|
+
resolvedConfigPath = normalizePath(hcPath);
|
|
34
|
+
// This direct dependency on a real file
|
|
35
|
+
// makes HMR work for the virtual module.
|
|
36
|
+
return this.resolve(hcPath, importer, { skipSelf: true });
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
if ([
|
|
36
40
|
VIRTUAL_PROXY_HYDROGEN_CONFIG_ID,
|
|
@@ -47,7 +51,7 @@ export default (pluginOptions) => {
|
|
|
47
51
|
// Likely due to a bug in Vite, but virtual modules cannot be loaded
|
|
48
52
|
// directly using ssrLoadModule from a Vite plugin. It needs to be proxied as follows:
|
|
49
53
|
if (id === '\0' + VIRTUAL_PROXY_HYDROGEN_CONFIG_ID) {
|
|
50
|
-
return `import hc from '${VIRTUAL_HYDROGEN_CONFIG_ID}'; export default hc;`;
|
|
54
|
+
return `import hc from '${VIRTUAL_HYDROGEN_CONFIG_ID}'; export default typeof hc === 'function' ? hc() : hc;`;
|
|
51
55
|
}
|
|
52
56
|
if (id === '\0' + VIRTUAL_PROXY_HYDROGEN_ROUTES_ID) {
|
|
53
57
|
return `import hr from '${VIRTUAL_HYDROGEN_ROUTES_ID}'; export default hr;`;
|
|
@@ -82,13 +86,27 @@ export default (pluginOptions) => {
|
|
|
82
86
|
});
|
|
83
87
|
}
|
|
84
88
|
},
|
|
89
|
+
transform(code, id) {
|
|
90
|
+
if (id === resolvedConfigPath) {
|
|
91
|
+
const s = new MagicString(code);
|
|
92
|
+
// Wrap in function to avoid evaluating `Oxygen.env`
|
|
93
|
+
// in the config until we have polyfilled it properly.
|
|
94
|
+
s.replace(/export\s+default\s+(\w+)\s*\(/g, (all, m1) => all.replace(m1, `() => ${m1}`));
|
|
95
|
+
return {
|
|
96
|
+
code: s.toString(),
|
|
97
|
+
map: s.generateMap({ file: id, source: id }),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
},
|
|
85
101
|
};
|
|
86
102
|
async function importHydrogenConfig() {
|
|
87
103
|
if (server) {
|
|
88
104
|
const loaded = await server.ssrLoadModule(VIRTUAL_PROXY_HYDROGEN_CONFIG_ID);
|
|
89
105
|
return loaded.default;
|
|
90
106
|
}
|
|
91
|
-
const { loaded } = await viteception([VIRTUAL_PROXY_HYDROGEN_CONFIG_ID]
|
|
107
|
+
const { loaded } = await viteception([VIRTUAL_PROXY_HYDROGEN_CONFIG_ID], {
|
|
108
|
+
root: config.root,
|
|
109
|
+
});
|
|
92
110
|
return loaded[0].default;
|
|
93
111
|
}
|
|
94
112
|
};
|
|
@@ -3,7 +3,7 @@ import { getLoggerWithContext, logServerResponse, } from '../utilities/log/index
|
|
|
3
3
|
import { fetchBuilder, graphqlRequestBody } from './fetch.js';
|
|
4
4
|
import { getStorefrontApiRequestHeaders } from './storefrontApi.js';
|
|
5
5
|
import { emptySessionImplementation } from '../foundation/session/session.js';
|
|
6
|
-
import { RSC_PATHNAME } from '../constants.js';
|
|
6
|
+
import { FORM_REDIRECT_COOKIE, RSC_PATHNAME } from '../constants.js';
|
|
7
7
|
let memoizedApiRoutes = [];
|
|
8
8
|
let memoizedRawRoutes = {};
|
|
9
9
|
export function extractPathFromRoutesKey(routesKey, dirPrefix) {
|
|
@@ -109,6 +109,15 @@ export async function renderApiRoute(request, route, hydrogenConfig, { session,
|
|
|
109
109
|
hydrogenConfig,
|
|
110
110
|
session: session
|
|
111
111
|
? {
|
|
112
|
+
async getFlash(key) {
|
|
113
|
+
const data = await session.get(request);
|
|
114
|
+
const value = data[key];
|
|
115
|
+
if (value) {
|
|
116
|
+
delete data[key];
|
|
117
|
+
await session.set(request, data);
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
},
|
|
112
121
|
async get() {
|
|
113
122
|
return session.get(request);
|
|
114
123
|
},
|
|
@@ -166,6 +175,7 @@ export async function renderApiRoute(request, route, hydrogenConfig, { session,
|
|
|
166
175
|
// Doing so prevents odd refresh / back behavior. The redirect response also should *never* be cached.
|
|
167
176
|
response.headers.set('Location', newUrl.href);
|
|
168
177
|
response.headers.set('Cache-Control', 'no-store');
|
|
178
|
+
response.headers.append('Set-Cookie', `${FORM_REDIRECT_COOKIE}=1`);
|
|
169
179
|
return new Response(null, {
|
|
170
180
|
status: 303,
|
|
171
181
|
headers: response.headers,
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "1.
|
|
1
|
+
export declare const LIB_VERSION = "1.3.0";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '1.
|
|
1
|
+
export const LIB_VERSION = '1.3.0';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export declare type SessionSyncApi = {
|
|
2
2
|
get: () => Record<string, string>;
|
|
3
|
+
set: (data: Record<string, any>) => any;
|
|
3
4
|
};
|
|
4
5
|
export declare type SessionApi = {
|
|
5
6
|
get: () => Promise<Record<string, string>>;
|
|
6
7
|
set: (key: string, value: string) => Promise<void>;
|
|
7
8
|
destroy: () => Promise<void>;
|
|
9
|
+
getFlash: (key: string) => any;
|
|
8
10
|
};
|
|
9
11
|
export declare type SessionStorageAdapter = {
|
|
10
12
|
get: (request: Request) => Promise<Record<string, string>>;
|
|
@@ -9,7 +9,6 @@ const vite_plugin_hydrogen_virtual_files_js_1 = __importDefault(require("./plugi
|
|
|
9
9
|
const vite_plugin_platform_entry_js_1 = __importDefault(require("./plugins/vite-plugin-platform-entry.js"));
|
|
10
10
|
const vite_plugin_hydrogen_rsc_js_1 = __importDefault(require("./plugins/vite-plugin-hydrogen-rsc.js"));
|
|
11
11
|
const vite_plugin_ssr_interop_js_1 = __importDefault(require("./plugins/vite-plugin-ssr-interop.js"));
|
|
12
|
-
const vite_plugin_purge_query_cache_js_1 = __importDefault(require("./plugins/vite-plugin-purge-query-cache.js"));
|
|
13
12
|
const vite_plugin_hydration_auto_import_js_1 = __importDefault(require("./plugins/vite-plugin-hydration-auto-import.js"));
|
|
14
13
|
const vite_plugin_inspect_1 = __importDefault(require("vite-plugin-inspect"));
|
|
15
14
|
const plugin_react_1 = __importDefault(require("@vitejs/plugin-react"));
|
|
@@ -17,10 +16,11 @@ const vite_plugin_css_rsc_js_1 = __importDefault(require("./plugins/vite-plugin-
|
|
|
17
16
|
const vite_plugin_css_modules_rsc_js_1 = __importDefault(require("./plugins/vite-plugin-css-modules-rsc.js"));
|
|
18
17
|
const vite_plugin_client_imports_js_1 = __importDefault(require("./plugins/vite-plugin-client-imports.js"));
|
|
19
18
|
const vite_plugin_hydrogen_suppress_warnings_js_1 = __importDefault(require("./plugins/vite-plugin-hydrogen-suppress-warnings.js"));
|
|
19
|
+
const vite_plugin_assets_version_js_1 = __importDefault(require("./plugins/vite-plugin-assets-version.js"));
|
|
20
20
|
const hydrogenPlugin = (pluginOptions = {}) => {
|
|
21
21
|
return [
|
|
22
22
|
process.env.VITE_INSPECT && (0, vite_plugin_inspect_1.default)(),
|
|
23
|
-
(0, vite_plugin_hydrogen_config_js_1.default)(),
|
|
23
|
+
(0, vite_plugin_hydrogen_config_js_1.default)(pluginOptions),
|
|
24
24
|
(0, vite_plugin_hydrogen_client_middleware_js_1.default)(),
|
|
25
25
|
(0, vite_plugin_client_imports_js_1.default)(),
|
|
26
26
|
(0, vite_plugin_hydrogen_middleware_js_1.default)(pluginOptions),
|
|
@@ -32,7 +32,8 @@ const hydrogenPlugin = (pluginOptions = {}) => {
|
|
|
32
32
|
(0, vite_plugin_hydrogen_rsc_js_1.default)(pluginOptions),
|
|
33
33
|
(0, vite_plugin_platform_entry_js_1.default)(),
|
|
34
34
|
(0, vite_plugin_hydrogen_suppress_warnings_js_1.default)(),
|
|
35
|
-
pluginOptions.
|
|
35
|
+
pluginOptions.assetHashVersion &&
|
|
36
|
+
(0, vite_plugin_assets_version_js_1.default)(pluginOptions.assetHashVersion),
|
|
36
37
|
];
|
|
37
38
|
};
|
|
38
39
|
exports.default = hydrogenPlugin; // For ESM
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function assetsVersion(version) {
|
|
4
|
+
return {
|
|
5
|
+
name: 'hydrogen:augment-with-version',
|
|
6
|
+
augmentChunkHash() {
|
|
7
|
+
return version ?? '';
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
exports.default = assetsVersion;
|
|
@@ -40,7 +40,6 @@ function cssRsc() {
|
|
|
40
40
|
if (server) {
|
|
41
41
|
const tags = [];
|
|
42
42
|
const foundCssFiles = new Set();
|
|
43
|
-
const { browserHash = '' } = server._optimizedDeps?.metadata || {};
|
|
44
43
|
for (const [key, value] of server.moduleGraph.idToModuleMap.entries()) {
|
|
45
44
|
if (
|
|
46
45
|
// Note: Some CSS-in-JS libraries use `.css.js`
|
|
@@ -60,10 +59,6 @@ function cssRsc() {
|
|
|
60
59
|
? url.replace('?', timestampQuery + '&')
|
|
61
60
|
: url + timestampQuery;
|
|
62
61
|
}
|
|
63
|
-
if (browserHash && !url.includes('v=')) {
|
|
64
|
-
// Append the hash at the end
|
|
65
|
-
url += (url.includes('?') ? '&' : '?') + `v=${browserHash}`;
|
|
66
|
-
}
|
|
67
62
|
tags.push(value.type === 'css'
|
|
68
63
|
? { tag: 'link', attrs: { rel: 'stylesheet', href: url } }
|
|
69
64
|
: { tag: 'script', attrs: { type: 'module', src: url } });
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
6
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
+
exports.default = (pluginOptions) => {
|
|
4
8
|
const rollupOptions = {
|
|
5
9
|
output: {},
|
|
6
10
|
};
|
|
@@ -25,7 +29,7 @@ exports.default = () => {
|
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
return {
|
|
28
|
-
name: '
|
|
32
|
+
name: 'hydrogen:config',
|
|
29
33
|
config: async (config, env) => ({
|
|
30
34
|
resolve: {
|
|
31
35
|
alias: {
|
|
@@ -50,7 +54,7 @@ exports.default = () => {
|
|
|
50
54
|
* Tell Vite to bundle everything when we're building for Workers.
|
|
51
55
|
* Otherwise, bundle RSC plugin as a workaround to apply the vendor alias above.
|
|
52
56
|
*/
|
|
53
|
-
noExternal: isWorker || [/react-server-dom-vite/],
|
|
57
|
+
noExternal: isWorker || [/react-server-dom-vite/, /@shopify\/hydrogen/],
|
|
54
58
|
target: isWorker ? 'webworker' : 'node',
|
|
55
59
|
},
|
|
56
60
|
// Reload when updating local Hydrogen lib
|
|
@@ -95,7 +99,10 @@ exports.default = () => {
|
|
|
95
99
|
define: {
|
|
96
100
|
__HYDROGEN_DEV__: env.mode !== 'production',
|
|
97
101
|
__HYDROGEN_WORKER__: isWorker,
|
|
98
|
-
__HYDROGEN_TEST__: false,
|
|
102
|
+
__HYDROGEN_TEST__: false,
|
|
103
|
+
__HYDROGEN_CACHE_ID__: pluginOptions.purgeQueryCacheOnBuild
|
|
104
|
+
? `"${crypto_1.default.randomBytes(8).toString('hex').slice(0, 8)}"`
|
|
105
|
+
: '"__QUERY_CACHE_ID__"',
|
|
99
106
|
},
|
|
100
107
|
envPrefix: ['VITE_', 'PUBLIC_'],
|
|
101
108
|
base: process.env.HYDROGEN_ASSET_BASE_URL,
|
|
@@ -8,6 +8,7 @@ const vite_1 = require("vite");
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
10
|
const viteception_js_1 = require("../viteception.js");
|
|
11
|
+
const magic_string_1 = __importDefault(require("magic-string"));
|
|
11
12
|
exports.HYDROGEN_DEFAULT_SERVER_ENTRY = process.env.HYDROGEN_SERVER_ENTRY || '/src/App.server';
|
|
12
13
|
// The character ":" breaks Vite with Node >= 16.15. Use "_" instead
|
|
13
14
|
const VIRTUAL_PREFIX = 'virtual__';
|
|
@@ -23,6 +24,7 @@ exports.VIRTUAL_PROXY_HYDROGEN_ROUTES_ID = VIRTUAL_PREFIX + PROXY_PREFIX + HYDRO
|
|
|
23
24
|
exports.default = (pluginOptions) => {
|
|
24
25
|
let config;
|
|
25
26
|
let server;
|
|
27
|
+
let resolvedConfigPath;
|
|
26
28
|
return {
|
|
27
29
|
name: 'hydrogen:virtual-files',
|
|
28
30
|
configResolved(_config) {
|
|
@@ -33,10 +35,12 @@ exports.default = (pluginOptions) => {
|
|
|
33
35
|
},
|
|
34
36
|
resolveId(source, importer) {
|
|
35
37
|
if (source === VIRTUAL_HYDROGEN_CONFIG_ID) {
|
|
36
|
-
return findHydrogenConfigPath(config.root, pluginOptions.configPath).then((hcPath) =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
return findHydrogenConfigPath(config.root, pluginOptions.configPath).then((hcPath) => {
|
|
39
|
+
resolvedConfigPath = (0, vite_1.normalizePath)(hcPath);
|
|
40
|
+
// This direct dependency on a real file
|
|
41
|
+
// makes HMR work for the virtual module.
|
|
42
|
+
return this.resolve(hcPath, importer, { skipSelf: true });
|
|
43
|
+
});
|
|
40
44
|
}
|
|
41
45
|
if ([
|
|
42
46
|
exports.VIRTUAL_PROXY_HYDROGEN_CONFIG_ID,
|
|
@@ -53,7 +57,7 @@ exports.default = (pluginOptions) => {
|
|
|
53
57
|
// Likely due to a bug in Vite, but virtual modules cannot be loaded
|
|
54
58
|
// directly using ssrLoadModule from a Vite plugin. It needs to be proxied as follows:
|
|
55
59
|
if (id === '\0' + exports.VIRTUAL_PROXY_HYDROGEN_CONFIG_ID) {
|
|
56
|
-
return `import hc from '${VIRTUAL_HYDROGEN_CONFIG_ID}'; export default hc;`;
|
|
60
|
+
return `import hc from '${VIRTUAL_HYDROGEN_CONFIG_ID}'; export default typeof hc === 'function' ? hc() : hc;`;
|
|
57
61
|
}
|
|
58
62
|
if (id === '\0' + exports.VIRTUAL_PROXY_HYDROGEN_ROUTES_ID) {
|
|
59
63
|
return `import hr from '${VIRTUAL_HYDROGEN_ROUTES_ID}'; export default hr;`;
|
|
@@ -88,13 +92,27 @@ exports.default = (pluginOptions) => {
|
|
|
88
92
|
});
|
|
89
93
|
}
|
|
90
94
|
},
|
|
95
|
+
transform(code, id) {
|
|
96
|
+
if (id === resolvedConfigPath) {
|
|
97
|
+
const s = new magic_string_1.default(code);
|
|
98
|
+
// Wrap in function to avoid evaluating `Oxygen.env`
|
|
99
|
+
// in the config until we have polyfilled it properly.
|
|
100
|
+
s.replace(/export\s+default\s+(\w+)\s*\(/g, (all, m1) => all.replace(m1, `() => ${m1}`));
|
|
101
|
+
return {
|
|
102
|
+
code: s.toString(),
|
|
103
|
+
map: s.generateMap({ file: id, source: id }),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
},
|
|
91
107
|
};
|
|
92
108
|
async function importHydrogenConfig() {
|
|
93
109
|
if (server) {
|
|
94
110
|
const loaded = await server.ssrLoadModule(exports.VIRTUAL_PROXY_HYDROGEN_CONFIG_ID);
|
|
95
111
|
return loaded.default;
|
|
96
112
|
}
|
|
97
|
-
const { loaded } = await (0, viteception_js_1.viteception)([exports.VIRTUAL_PROXY_HYDROGEN_CONFIG_ID]
|
|
113
|
+
const { loaded } = await (0, viteception_js_1.viteception)([exports.VIRTUAL_PROXY_HYDROGEN_CONFIG_ID], {
|
|
114
|
+
root: config.root,
|
|
115
|
+
});
|
|
98
116
|
return loaded[0].default;
|
|
99
117
|
}
|
|
100
118
|
};
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=14"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.3.0",
|
|
11
11
|
"description": "Modern custom Shopify storefronts",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"main": "dist/esnext/index.js",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"@rollup/plugin-graphql": "^1.0.0",
|
|
92
92
|
"@testing-library/jest-dom": "^5.16.4",
|
|
93
93
|
"@testing-library/react": "^13.3.0",
|
|
94
|
+
"@testing-library/user-event": "^14.3.0",
|
|
94
95
|
"@types/body-parser": "^1.19.2",
|
|
95
96
|
"@types/connect": "^3.4.34",
|
|
96
97
|
"@types/graphql": "^14.5.0",
|
|
@@ -104,13 +105,13 @@
|
|
|
104
105
|
"babel-loader": "^8.2.2",
|
|
105
106
|
"cpy-cli": "^3.1.0",
|
|
106
107
|
"eslint-plugin-import": "^2.26.0",
|
|
107
|
-
"happy-dom": "^6.0.
|
|
108
|
+
"happy-dom": "^6.0.4",
|
|
108
109
|
"mkdirp": "^1.0.4",
|
|
109
110
|
"npm-run-all": "^4.1.5",
|
|
110
111
|
"postcss": "^8",
|
|
111
112
|
"raw-loader": "^4.0.2",
|
|
112
113
|
"rimraf": "^3.0.2",
|
|
113
|
-
"vitest": "^0.
|
|
114
|
+
"vitest": "^0.22.0"
|
|
114
115
|
},
|
|
115
116
|
"peerDependencies": {
|
|
116
117
|
"body-parser": "^1.20.0",
|
|
@@ -128,10 +128,10 @@ function ReactFlightVitePlugin() {
|
|
|
128
128
|
enforce: 'pre',
|
|
129
129
|
buildStart: function () {
|
|
130
130
|
// Let other plugins differentiate between pure SSR and RSC builds
|
|
131
|
-
if (config?.build?.ssr) process.env.
|
|
131
|
+
if (config?.build?.ssr) process.env.VITE_RSC_BUILD = 'true';
|
|
132
132
|
},
|
|
133
133
|
buildEnd: function () {
|
|
134
|
-
if (config?.build?.ssr) delete process.env.
|
|
134
|
+
if (config?.build?.ssr) delete process.env.VITE_RSC_BUILD;
|
|
135
135
|
},
|
|
136
136
|
configureServer: function (_server) {
|
|
137
137
|
server = _server;
|
|
@@ -302,7 +302,7 @@ function ReactFlightVitePlugin() {
|
|
|
302
302
|
throw new Error('[react-server-dom-vite] Parameter serverBuildEntries is required for client build');
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
return findClientBoundariesForClientBuild(serverBuildEntries, optimizeBoundaries !== false).then(injectGlobs);
|
|
305
|
+
return findClientBoundariesForClientBuild(serverBuildEntries, optimizeBoundaries !== false, config.root).then(injectGlobs);
|
|
306
306
|
}
|
|
307
307
|
},
|
|
308
308
|
handleHotUpdate: function (_ref2) {
|
|
@@ -405,9 +405,10 @@ function findClientBoundaries(moduleGraph) {
|
|
|
405
405
|
return clientBoundaries;
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
async function findClientBoundariesForClientBuild(serverEntries, optimizeBoundaries) {
|
|
408
|
+
async function findClientBoundariesForClientBuild(serverEntries, optimizeBoundaries, root) {
|
|
409
409
|
// Viteception
|
|
410
410
|
var server = await vite.createServer({
|
|
411
|
+
root: root,
|
|
411
412
|
clearScreen: false,
|
|
412
413
|
server: {
|
|
413
414
|
middlewareMode: 'ssr'
|
|
@@ -124,10 +124,10 @@ function ReactFlightVitePlugin() {
|
|
|
124
124
|
enforce: 'pre',
|
|
125
125
|
buildStart: function () {
|
|
126
126
|
// Let other plugins differentiate between pure SSR and RSC builds
|
|
127
|
-
if (config?.build?.ssr) process.env.
|
|
127
|
+
if (config?.build?.ssr) process.env.VITE_RSC_BUILD = 'true';
|
|
128
128
|
},
|
|
129
129
|
buildEnd: function () {
|
|
130
|
-
if (config?.build?.ssr) delete process.env.
|
|
130
|
+
if (config?.build?.ssr) delete process.env.VITE_RSC_BUILD;
|
|
131
131
|
},
|
|
132
132
|
configureServer: function (_server) {
|
|
133
133
|
server = _server;
|
|
@@ -298,7 +298,7 @@ function ReactFlightVitePlugin() {
|
|
|
298
298
|
throw new Error('[react-server-dom-vite] Parameter serverBuildEntries is required for client build');
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
return findClientBoundariesForClientBuild(serverBuildEntries, optimizeBoundaries !== false).then(injectGlobs);
|
|
301
|
+
return findClientBoundariesForClientBuild(serverBuildEntries, optimizeBoundaries !== false, config.root).then(injectGlobs);
|
|
302
302
|
}
|
|
303
303
|
},
|
|
304
304
|
handleHotUpdate: function (_ref2) {
|
|
@@ -401,9 +401,10 @@ function findClientBoundaries(moduleGraph) {
|
|
|
401
401
|
return clientBoundaries;
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
async function findClientBoundariesForClientBuild(serverEntries, optimizeBoundaries) {
|
|
404
|
+
async function findClientBoundariesForClientBuild(serverEntries, optimizeBoundaries, root) {
|
|
405
405
|
// Viteception
|
|
406
406
|
var server = await createServer({
|
|
407
|
+
root: root,
|
|
407
408
|
clearScreen: false,
|
|
408
409
|
server: {
|
|
409
410
|
middlewareMode: 'ssr'
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import Crypto from 'crypto';
|
|
2
|
-
export default () => {
|
|
3
|
-
const buildCacheId = Crypto.randomBytes(8).toString('hex').slice(0, 8);
|
|
4
|
-
return {
|
|
5
|
-
name: 'vite-plugin-purge-query-cache',
|
|
6
|
-
enforce: 'pre',
|
|
7
|
-
transform(code) {
|
|
8
|
-
return code.replace('__QUERY_CACHE_ID__', buildCacheId);
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
-
exports.default = () => {
|
|
8
|
-
const buildCacheId = crypto_1.default.randomBytes(8).toString('hex').slice(0, 8);
|
|
9
|
-
return {
|
|
10
|
-
name: 'vite-plugin-purge-query-cache',
|
|
11
|
-
enforce: 'pre',
|
|
12
|
-
transform(code) {
|
|
13
|
-
return code.replace('__QUERY_CACHE_ID__', buildCacheId);
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
};
|