@shopify/cli-hydrogen 8.1.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/hydrogen/starter/CHANGELOG.md +166 -0
- package/dist/assets/hydrogen/starter/app/components/AddToCartButton.tsx +37 -0
- package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +150 -0
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +68 -0
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +101 -0
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +3 -3
- package/dist/assets/hydrogen/starter/app/components/PageLayout.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/components/ProductForm.tsx +80 -0
- package/dist/assets/hydrogen/starter/app/components/ProductImage.tsx +23 -0
- package/dist/assets/hydrogen/starter/app/components/ProductPrice.tsx +27 -0
- package/dist/assets/hydrogen/starter/app/lib/session.ts +5 -0
- package/dist/assets/hydrogen/starter/app/root.tsx +23 -36
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +1 -5
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +12 -70
- package/dist/assets/hydrogen/starter/app/routes/account.orders.$id.tsx +7 -14
- package/dist/assets/hydrogen/starter/app/routes/account.orders._index.tsx +1 -8
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +5 -22
- package/dist/assets/hydrogen/starter/app/routes/account.tsx +0 -1
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +1 -3
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +51 -232
- package/dist/assets/hydrogen/starter/package.json +10 -11
- package/dist/assets/hydrogen/starter/server.ts +4 -0
- package/dist/assets/hydrogen/tailwind/package.json +1 -6
- package/dist/assets/hydrogen/tailwind/tailwind.css +6 -3
- package/dist/assets/hydrogen/vanilla-extract/package.json +2 -3
- package/dist/assets/hydrogen/virtual-routes/components/{Layout.jsx → PageLayout.jsx} +2 -2
- package/dist/assets/hydrogen/virtual-routes/components/RequestDetails.jsx +1 -2
- package/dist/assets/hydrogen/virtual-routes/components/RequestTable.jsx +1 -2
- package/dist/assets/hydrogen/virtual-routes/routes/index.jsx +1 -2
- package/dist/assets/hydrogen/virtual-routes/virtual-root.jsx +8 -30
- package/dist/commands/hydrogen/build.js +33 -10
- package/dist/commands/hydrogen/customer-account/push.js +3 -6
- package/dist/commands/hydrogen/debug/cpu.js +3 -3
- package/dist/commands/hydrogen/deploy.js +14 -3
- package/dist/commands/hydrogen/dev.js +3 -6
- package/dist/commands/hydrogen/env/list.js +1 -2
- package/dist/commands/hydrogen/env/pull.js +2 -4
- package/dist/commands/hydrogen/env/push.js +6 -12
- package/dist/commands/hydrogen/init.d.ts +18 -15
- package/dist/commands/hydrogen/init.js +12 -24
- package/dist/commands/hydrogen/link.js +1 -2
- package/dist/commands/hydrogen/preview.js +4 -6
- package/dist/commands/hydrogen/setup/css.js +29 -12
- package/dist/commands/hydrogen/setup/vite.js +3 -6
- package/dist/commands/hydrogen/setup.js +8 -7
- package/dist/commands/hydrogen/upgrade.js +16 -32
- package/dist/hooks/init.js +50 -6
- package/dist/index.d.ts +46 -46
- package/dist/lib/auth.js +1 -2
- package/dist/lib/build.js +1 -2
- package/dist/lib/bundle/analyzer.js +39 -24
- package/dist/lib/bundle/vite-plugin.js +161 -0
- package/dist/lib/check-cli-version.js +61 -0
- package/dist/lib/check-lockfile.js +2 -2
- package/dist/lib/classic-compiler/build.js +3 -3
- package/dist/lib/classic-compiler/dev.js +5 -10
- package/dist/lib/codegen.js +8 -16
- package/dist/lib/defer.js +2 -4
- package/dist/lib/environment-variables.js +2 -4
- package/dist/lib/file.js +15 -7
- package/dist/lib/flags.js +10 -0
- package/dist/lib/get-oxygen-deployment-data.js +1 -2
- package/dist/lib/graphiql-url.js +1 -2
- package/dist/lib/import-utils.js +3 -2
- package/dist/lib/log.js +11 -22
- package/dist/lib/mini-oxygen/common.js +1 -2
- package/dist/lib/mini-oxygen/node.js +1 -2
- package/dist/lib/missing-routes.js +1 -2
- package/dist/lib/onboarding/common.js +60 -15
- package/dist/lib/onboarding/local.js +14 -13
- package/dist/lib/onboarding/remote.js +16 -9
- package/dist/lib/onboarding/setup-template.mocks.js +6 -3
- package/dist/lib/remix-config.js +2 -4
- package/dist/lib/remix-version-check.js +1 -2
- package/dist/lib/request-events.js +3 -6
- package/dist/lib/setups/css/assets.js +1 -1
- package/dist/lib/setups/css/index.js +17 -10
- package/dist/lib/setups/css/replacers.js +74 -76
- package/dist/lib/setups/css/tailwind.js +16 -20
- package/dist/lib/setups/css/vanilla-extract.js +8 -5
- package/dist/lib/setups/i18n/replacers.js +1 -2
- package/dist/lib/setups/routes/generate.js +18 -19
- package/dist/lib/shell.js +5 -10
- package/dist/lib/template-diff.js +83 -104
- package/dist/lib/template-downloader.js +2 -2
- package/dist/lib/transpile/morph/functions.js +3 -6
- package/dist/lib/transpile/morph/index.js +2 -4
- package/dist/lib/transpile/morph/typedefs.js +3 -6
- package/dist/lib/transpile/morph/utils.js +2 -4
- package/dist/lib/transpile/project.js +4 -3
- package/oclif.manifest.json +51 -4
- package/package.json +8 -12
- package/dist/assets/hydrogen/css-modules/package.json +0 -6
- package/dist/assets/hydrogen/postcss/package.json +0 -10
- package/dist/assets/hydrogen/postcss/postcss.config.js +0 -8
- package/dist/assets/hydrogen/starter/app/components/Cart.tsx +0 -364
- package/dist/assets/hydrogen/tailwind/postcss.config.js +0 -10
- package/dist/assets/hydrogen/tailwind/tailwind.config.js +0 -8
- package/dist/lib/check-version.js +0 -75
- package/dist/lib/setups/css/css-modules.js +0 -23
- package/dist/lib/setups/css/postcss.js +0 -31
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import {Suspense} from 'react';
|
|
2
2
|
import {defer, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
3
|
+
import {Await, useLoaderData, type MetaFunction} from '@remix-run/react';
|
|
4
|
+
import type {ProductFragment} from 'storefrontapi.generated';
|
|
3
5
|
import {
|
|
4
|
-
Await,
|
|
5
|
-
Link,
|
|
6
|
-
useLoaderData,
|
|
7
|
-
type MetaFunction,
|
|
8
|
-
type FetcherWithComponents,
|
|
9
|
-
} from '@remix-run/react';
|
|
10
|
-
import type {
|
|
11
|
-
ProductFragment,
|
|
12
|
-
ProductVariantsQuery,
|
|
13
|
-
ProductVariantFragment,
|
|
14
|
-
} from 'storefrontapi.generated';
|
|
15
|
-
import {
|
|
16
|
-
Image,
|
|
17
|
-
Money,
|
|
18
|
-
VariantSelector,
|
|
19
|
-
type VariantOption,
|
|
20
6
|
getSelectedProductOptions,
|
|
21
|
-
CartForm,
|
|
22
|
-
type OptimisticCartLine,
|
|
23
7
|
Analytics,
|
|
24
|
-
|
|
25
|
-
useAnalytics,
|
|
8
|
+
useOptimisticVariant,
|
|
26
9
|
} from '@shopify/hydrogen';
|
|
27
10
|
import type {SelectedOption} from '@shopify/hydrogen/storefront-api-types';
|
|
28
11
|
import {getVariantUrl} from '~/lib/variants';
|
|
29
|
-
import {
|
|
12
|
+
import {ProductPrice} from '~/components/ProductPrice';
|
|
13
|
+
import {ProductImage} from '~/components/ProductImage';
|
|
14
|
+
import {ProductForm} from '~/components/ProductForm';
|
|
30
15
|
|
|
31
16
|
export const meta: MetaFunction<typeof loader> = ({data}) => {
|
|
32
17
|
return [{title: `Hydrogen | ${data?.product.title ?? ''}`}];
|
|
@@ -143,15 +128,54 @@ function redirectToFirstVariant({
|
|
|
143
128
|
|
|
144
129
|
export default function Product() {
|
|
145
130
|
const {product, variants} = useLoaderData<typeof loader>();
|
|
146
|
-
const
|
|
131
|
+
const selectedVariant = useOptimisticVariant(
|
|
132
|
+
product.selectedVariant,
|
|
133
|
+
variants,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const {title, descriptionHtml} = product;
|
|
137
|
+
|
|
147
138
|
return (
|
|
148
139
|
<div className="product">
|
|
149
140
|
<ProductImage image={selectedVariant?.image} />
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
141
|
+
<div className="product-main">
|
|
142
|
+
<h1>{title}</h1>
|
|
143
|
+
<ProductPrice
|
|
144
|
+
price={selectedVariant?.price}
|
|
145
|
+
compareAtPrice={selectedVariant?.compareAtPrice}
|
|
146
|
+
/>
|
|
147
|
+
<br />
|
|
148
|
+
<Suspense
|
|
149
|
+
fallback={
|
|
150
|
+
<ProductForm
|
|
151
|
+
product={product}
|
|
152
|
+
selectedVariant={selectedVariant}
|
|
153
|
+
variants={[]}
|
|
154
|
+
/>
|
|
155
|
+
}
|
|
156
|
+
>
|
|
157
|
+
<Await
|
|
158
|
+
errorElement="There was a problem loading product variants"
|
|
159
|
+
resolve={variants}
|
|
160
|
+
>
|
|
161
|
+
{(data) => (
|
|
162
|
+
<ProductForm
|
|
163
|
+
product={product}
|
|
164
|
+
selectedVariant={selectedVariant}
|
|
165
|
+
variants={data?.product?.variants.nodes || []}
|
|
166
|
+
/>
|
|
167
|
+
)}
|
|
168
|
+
</Await>
|
|
169
|
+
</Suspense>
|
|
170
|
+
<br />
|
|
171
|
+
<br />
|
|
172
|
+
<p>
|
|
173
|
+
<strong>Description</strong>
|
|
174
|
+
</p>
|
|
175
|
+
<br />
|
|
176
|
+
<div dangerouslySetInnerHTML={{__html: descriptionHtml}} />
|
|
177
|
+
<br />
|
|
178
|
+
</div>
|
|
155
179
|
<Analytics.ProductView
|
|
156
180
|
data={{
|
|
157
181
|
products: [
|
|
@@ -171,211 +195,6 @@ export default function Product() {
|
|
|
171
195
|
);
|
|
172
196
|
}
|
|
173
197
|
|
|
174
|
-
function ProductImage({image}: {image: ProductVariantFragment['image']}) {
|
|
175
|
-
if (!image) {
|
|
176
|
-
return <div className="product-image" />;
|
|
177
|
-
}
|
|
178
|
-
return (
|
|
179
|
-
<div className="product-image">
|
|
180
|
-
<Image
|
|
181
|
-
alt={image.altText || 'Product Image'}
|
|
182
|
-
aspectRatio="1/1"
|
|
183
|
-
data={image}
|
|
184
|
-
key={image.id}
|
|
185
|
-
sizes="(min-width: 45em) 50vw, 100vw"
|
|
186
|
-
/>
|
|
187
|
-
</div>
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function ProductMain({
|
|
192
|
-
selectedVariant,
|
|
193
|
-
product,
|
|
194
|
-
variants,
|
|
195
|
-
}: {
|
|
196
|
-
product: ProductFragment;
|
|
197
|
-
selectedVariant: ProductFragment['selectedVariant'];
|
|
198
|
-
variants: Promise<ProductVariantsQuery | null>;
|
|
199
|
-
}) {
|
|
200
|
-
const {title, descriptionHtml} = product;
|
|
201
|
-
return (
|
|
202
|
-
<div className="product-main">
|
|
203
|
-
<h1>{title}</h1>
|
|
204
|
-
<ProductPrice selectedVariant={selectedVariant} />
|
|
205
|
-
<br />
|
|
206
|
-
<Suspense
|
|
207
|
-
fallback={
|
|
208
|
-
<ProductForm
|
|
209
|
-
product={product}
|
|
210
|
-
selectedVariant={selectedVariant}
|
|
211
|
-
variants={[]}
|
|
212
|
-
/>
|
|
213
|
-
}
|
|
214
|
-
>
|
|
215
|
-
<Await
|
|
216
|
-
errorElement="There was a problem loading product variants"
|
|
217
|
-
resolve={variants}
|
|
218
|
-
>
|
|
219
|
-
{(data) => (
|
|
220
|
-
<ProductForm
|
|
221
|
-
product={product}
|
|
222
|
-
selectedVariant={selectedVariant}
|
|
223
|
-
variants={data?.product?.variants.nodes || []}
|
|
224
|
-
/>
|
|
225
|
-
)}
|
|
226
|
-
</Await>
|
|
227
|
-
</Suspense>
|
|
228
|
-
<br />
|
|
229
|
-
<br />
|
|
230
|
-
<p>
|
|
231
|
-
<strong>Description</strong>
|
|
232
|
-
</p>
|
|
233
|
-
<br />
|
|
234
|
-
<div dangerouslySetInnerHTML={{__html: descriptionHtml}} />
|
|
235
|
-
<br />
|
|
236
|
-
</div>
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function ProductPrice({
|
|
241
|
-
selectedVariant,
|
|
242
|
-
}: {
|
|
243
|
-
selectedVariant: ProductFragment['selectedVariant'];
|
|
244
|
-
}) {
|
|
245
|
-
return (
|
|
246
|
-
<div className="product-price">
|
|
247
|
-
{selectedVariant?.compareAtPrice ? (
|
|
248
|
-
<>
|
|
249
|
-
<p>Sale</p>
|
|
250
|
-
<br />
|
|
251
|
-
<div className="product-price-on-sale">
|
|
252
|
-
{selectedVariant ? <Money data={selectedVariant.price} /> : null}
|
|
253
|
-
<s>
|
|
254
|
-
<Money data={selectedVariant.compareAtPrice} />
|
|
255
|
-
</s>
|
|
256
|
-
</div>
|
|
257
|
-
</>
|
|
258
|
-
) : (
|
|
259
|
-
selectedVariant?.price && <Money data={selectedVariant?.price} />
|
|
260
|
-
)}
|
|
261
|
-
</div>
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function ProductForm({
|
|
266
|
-
product,
|
|
267
|
-
selectedVariant,
|
|
268
|
-
variants,
|
|
269
|
-
}: {
|
|
270
|
-
product: ProductFragment;
|
|
271
|
-
selectedVariant: ProductFragment['selectedVariant'];
|
|
272
|
-
variants: Array<ProductVariantFragment>;
|
|
273
|
-
}) {
|
|
274
|
-
const {open} = useAside();
|
|
275
|
-
const {publish, shop, cart, prevCart} = useAnalytics();
|
|
276
|
-
return (
|
|
277
|
-
<div className="product-form">
|
|
278
|
-
<VariantSelector
|
|
279
|
-
handle={product.handle}
|
|
280
|
-
options={product.options}
|
|
281
|
-
variants={variants}
|
|
282
|
-
>
|
|
283
|
-
{({option}) => <ProductOptions key={option.name} option={option} />}
|
|
284
|
-
</VariantSelector>
|
|
285
|
-
<br />
|
|
286
|
-
<AddToCartButton
|
|
287
|
-
disabled={!selectedVariant || !selectedVariant.availableForSale}
|
|
288
|
-
onClick={() => {
|
|
289
|
-
open('cart');
|
|
290
|
-
publish('cart_viewed', {
|
|
291
|
-
cart,
|
|
292
|
-
prevCart,
|
|
293
|
-
shop,
|
|
294
|
-
url: window.location.href || '',
|
|
295
|
-
} as CartViewPayload);
|
|
296
|
-
}}
|
|
297
|
-
lines={
|
|
298
|
-
selectedVariant
|
|
299
|
-
? [
|
|
300
|
-
{
|
|
301
|
-
merchandiseId: selectedVariant.id,
|
|
302
|
-
quantity: 1,
|
|
303
|
-
selectedVariant,
|
|
304
|
-
},
|
|
305
|
-
]
|
|
306
|
-
: []
|
|
307
|
-
}
|
|
308
|
-
>
|
|
309
|
-
{selectedVariant?.availableForSale ? 'Add to cart' : 'Sold out'}
|
|
310
|
-
</AddToCartButton>
|
|
311
|
-
</div>
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function ProductOptions({option}: {option: VariantOption}) {
|
|
316
|
-
return (
|
|
317
|
-
<div className="product-options" key={option.name}>
|
|
318
|
-
<h5>{option.name}</h5>
|
|
319
|
-
<div className="product-options-grid">
|
|
320
|
-
{option.values.map(({value, isAvailable, isActive, to}) => {
|
|
321
|
-
return (
|
|
322
|
-
<Link
|
|
323
|
-
className="product-options-item"
|
|
324
|
-
key={option.name + value}
|
|
325
|
-
prefetch="intent"
|
|
326
|
-
preventScrollReset
|
|
327
|
-
replace
|
|
328
|
-
to={to}
|
|
329
|
-
style={{
|
|
330
|
-
border: isActive ? '1px solid black' : '1px solid transparent',
|
|
331
|
-
opacity: isAvailable ? 1 : 0.3,
|
|
332
|
-
}}
|
|
333
|
-
>
|
|
334
|
-
{value}
|
|
335
|
-
</Link>
|
|
336
|
-
);
|
|
337
|
-
})}
|
|
338
|
-
</div>
|
|
339
|
-
<br />
|
|
340
|
-
</div>
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function AddToCartButton({
|
|
345
|
-
analytics,
|
|
346
|
-
children,
|
|
347
|
-
disabled,
|
|
348
|
-
lines,
|
|
349
|
-
onClick,
|
|
350
|
-
}: {
|
|
351
|
-
analytics?: unknown;
|
|
352
|
-
children: React.ReactNode;
|
|
353
|
-
disabled?: boolean;
|
|
354
|
-
lines: Array<OptimisticCartLine>;
|
|
355
|
-
onClick?: () => void;
|
|
356
|
-
}) {
|
|
357
|
-
return (
|
|
358
|
-
<CartForm route="/cart" inputs={{lines}} action={CartForm.ACTIONS.LinesAdd}>
|
|
359
|
-
{(fetcher: FetcherWithComponents<any>) => (
|
|
360
|
-
<>
|
|
361
|
-
<input
|
|
362
|
-
name="analytics"
|
|
363
|
-
type="hidden"
|
|
364
|
-
value={JSON.stringify(analytics)}
|
|
365
|
-
/>
|
|
366
|
-
<button
|
|
367
|
-
type="submit"
|
|
368
|
-
onClick={onClick}
|
|
369
|
-
disabled={disabled ?? fetcher.state !== 'idle'}
|
|
370
|
-
>
|
|
371
|
-
{children}
|
|
372
|
-
</button>
|
|
373
|
-
</>
|
|
374
|
-
)}
|
|
375
|
-
</CartForm>
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
198
|
const PRODUCT_VARIANT_FRAGMENT = `#graphql
|
|
380
199
|
fragment ProductVariant on ProductVariant {
|
|
381
200
|
availableForSale
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "skeleton",
|
|
3
3
|
"private": true,
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "2024.
|
|
5
|
+
"version": "2024.7.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "shopify hydrogen build --codegen",
|
|
@@ -14,12 +14,10 @@
|
|
|
14
14
|
},
|
|
15
15
|
"prettier": "@shopify/prettier-config",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@remix-run/react": "^2.
|
|
18
|
-
"@remix-run/server-runtime": "^2.
|
|
19
|
-
"@shopify/
|
|
20
|
-
"@shopify/
|
|
21
|
-
"@shopify/hydrogen": "2024.4.3",
|
|
22
|
-
"@shopify/remix-oxygen": "^2.0.4",
|
|
17
|
+
"@remix-run/react": "^2.10.1",
|
|
18
|
+
"@remix-run/server-runtime": "^2.10.1",
|
|
19
|
+
"@shopify/hydrogen": "2024.7.1",
|
|
20
|
+
"@shopify/remix-oxygen": "^2.0.5",
|
|
23
21
|
"graphql": "^16.6.0",
|
|
24
22
|
"graphql-tag": "^2.12.6",
|
|
25
23
|
"isbot": "^3.8.0",
|
|
@@ -28,11 +26,12 @@
|
|
|
28
26
|
},
|
|
29
27
|
"devDependencies": {
|
|
30
28
|
"@graphql-codegen/cli": "5.0.2",
|
|
31
|
-
"@remix-run/dev": "^2.
|
|
32
|
-
"@remix-run/eslint-config": "^2.
|
|
29
|
+
"@remix-run/dev": "^2.10.1",
|
|
30
|
+
"@remix-run/eslint-config": "^2.10.1",
|
|
31
|
+
"@shopify/cli": "^3.63.2",
|
|
33
32
|
"@shopify/hydrogen-codegen": "^0.3.1",
|
|
34
|
-
"@shopify/mini-oxygen": "^3.0.
|
|
35
|
-
"@shopify/oxygen-workers-types": "^4.
|
|
33
|
+
"@shopify/mini-oxygen": "^3.0.4",
|
|
34
|
+
"@shopify/oxygen-workers-types": "^4.1.2",
|
|
36
35
|
"@shopify/prettier-config": "^1.1.2",
|
|
37
36
|
"@total-typescript/ts-reset": "^0.4.2",
|
|
38
37
|
"@types/eslint": "^8.4.10",
|
|
@@ -96,6 +96,10 @@ export default {
|
|
|
96
96
|
|
|
97
97
|
const response = await handleRequest(request);
|
|
98
98
|
|
|
99
|
+
if (session.isPending) {
|
|
100
|
+
response.headers.set('Set-Cookie', await session.commit());
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
if (response.status === 404) {
|
|
100
104
|
/**
|
|
101
105
|
* Check for redirects only when there's a 404 from the app.
|
|
@@ -3,11 +3,6 @@
|
|
|
3
3
|
"defaults"
|
|
4
4
|
],
|
|
5
5
|
"devDependencies": {
|
|
6
|
-
"@tailwindcss/
|
|
7
|
-
"@tailwindcss/typography": "^0.5.9",
|
|
8
|
-
"postcss": "^8.4.21",
|
|
9
|
-
"postcss-import": "^15.1.0",
|
|
10
|
-
"postcss-preset-env": "^8.2.0",
|
|
11
|
-
"tailwindcss": "^3.3.0"
|
|
6
|
+
"@tailwindcss/vite": "4.0.0-alpha.17"
|
|
12
7
|
}
|
|
13
8
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"comment": "Remix version is automatically updated by the CLI",
|
|
3
2
|
"dependencies": {
|
|
4
|
-
"@
|
|
3
|
+
"@vanilla-extract/css": "^1.15.2"
|
|
5
4
|
},
|
|
6
5
|
"devDependencies": {
|
|
7
|
-
"@vanilla-extract/
|
|
6
|
+
"@vanilla-extract/vite-plugin": "^4.0.10"
|
|
8
7
|
}
|
|
9
8
|
}
|
|
@@ -34,8 +34,7 @@ function RequestDetails({
|
|
|
34
34
|
className: `tab${activeTabClass(key)}`,
|
|
35
35
|
onClick: () => setActiveTab(key),
|
|
36
36
|
onKeyUp: (event) => {
|
|
37
|
-
if (event.code === "Space")
|
|
38
|
-
setActiveTab(key);
|
|
37
|
+
if (event.code === "Space") setActiveTab(key);
|
|
39
38
|
},
|
|
40
39
|
children: TABS[key]
|
|
41
40
|
}
|
|
@@ -61,8 +61,7 @@ function RequestTable({
|
|
|
61
61
|
className: `grid-row${activeEventId === row.id ? " active" : ""}${row.status >= 400 ? " error" : ""}`,
|
|
62
62
|
onClick: () => setActiveEventId(row.id),
|
|
63
63
|
onKeyUp: (event) => {
|
|
64
|
-
if (event.code === "Space")
|
|
65
|
-
setActiveEventId(row.id);
|
|
64
|
+
if (event.code === "Space") setActiveEventId(row.id);
|
|
66
65
|
},
|
|
67
66
|
children: [
|
|
68
67
|
/* @__PURE__ */ jsx("div", { className: "grid-cell", children: row.url }),
|
|
@@ -47,8 +47,7 @@ function Index() {
|
|
|
47
47
|
} = useLoaderData();
|
|
48
48
|
let { name: shopName, id: shopId } = shop;
|
|
49
49
|
const configDone = shopId !== HYDROGEN_SHOP_ID && !isMockShop;
|
|
50
|
-
if (isMockShop || !shopName)
|
|
51
|
-
shopName = "Hydrogen";
|
|
50
|
+
if (isMockShop || !shopName) shopName = "Hydrogen";
|
|
52
51
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Layout, { shopName, children: [
|
|
53
52
|
configDone ? /* @__PURE__ */ jsx(HydrogenLogoBaseColor, {}) : /* @__PURE__ */ jsx(HydrogenLogoBaseBW, {}),
|
|
54
53
|
/* @__PURE__ */ jsxs("h1", { children: [
|
|
@@ -2,14 +2,13 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import {
|
|
3
3
|
Links,
|
|
4
4
|
Meta,
|
|
5
|
-
Outlet,
|
|
6
5
|
Scripts,
|
|
7
6
|
ScrollRestoration,
|
|
8
7
|
isRouteErrorResponse,
|
|
9
8
|
useRouteError
|
|
10
9
|
} from "@remix-run/react";
|
|
11
10
|
import favicon from "./assets/favicon.svg";
|
|
12
|
-
import {
|
|
11
|
+
import { PageLayout } from "./components/PageLayout.jsx";
|
|
13
12
|
import { useNonce } from "@shopify/hydrogen";
|
|
14
13
|
import styles from "./assets/styles.css?url";
|
|
15
14
|
const links = () => {
|
|
@@ -18,7 +17,7 @@ const links = () => {
|
|
|
18
17
|
{ rel: "icon", type: "image/svg+xml", href: favicon }
|
|
19
18
|
];
|
|
20
19
|
};
|
|
21
|
-
function
|
|
20
|
+
function Layout({ children }) {
|
|
22
21
|
const nonce = useNonce();
|
|
23
22
|
return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
|
|
24
23
|
/* @__PURE__ */ jsxs("head", { children: [
|
|
@@ -36,14 +35,13 @@ function App() {
|
|
|
36
35
|
/* @__PURE__ */ jsx(Links, {})
|
|
37
36
|
] }),
|
|
38
37
|
/* @__PURE__ */ jsxs("body", { children: [
|
|
39
|
-
/* @__PURE__ */ jsx(
|
|
38
|
+
/* @__PURE__ */ jsx(PageLayout, { children }),
|
|
40
39
|
/* @__PURE__ */ jsx(ScrollRestoration, { nonce }),
|
|
41
40
|
/* @__PURE__ */ jsx(Scripts, { nonce })
|
|
42
41
|
] })
|
|
43
42
|
] });
|
|
44
43
|
}
|
|
45
44
|
function ErrorBoundary() {
|
|
46
|
-
const nonce = useNonce();
|
|
47
45
|
const error = useRouteError();
|
|
48
46
|
let errorMessage = "Unknown error";
|
|
49
47
|
let errorStatus = 500;
|
|
@@ -53,34 +51,14 @@ function ErrorBoundary() {
|
|
|
53
51
|
} else if (error instanceof Error) {
|
|
54
52
|
errorMessage = error.message;
|
|
55
53
|
}
|
|
56
|
-
return /* @__PURE__ */ jsxs("
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/* @__PURE__ */ jsx("title", { children: "Hydrogen" }),
|
|
61
|
-
/* @__PURE__ */ jsx(
|
|
62
|
-
"meta",
|
|
63
|
-
{
|
|
64
|
-
name: "description",
|
|
65
|
-
content: "A custom storefront powered by Hydrogen"
|
|
66
|
-
}
|
|
67
|
-
),
|
|
68
|
-
/* @__PURE__ */ jsx(Meta, {}),
|
|
69
|
-
/* @__PURE__ */ jsx(Links, {})
|
|
70
|
-
] }),
|
|
71
|
-
/* @__PURE__ */ jsxs("body", { children: [
|
|
72
|
-
/* @__PURE__ */ jsx(Layout, { children: /* @__PURE__ */ jsxs("div", { className: "route-error", children: [
|
|
73
|
-
/* @__PURE__ */ jsx("h1", { children: "Please report this error" }),
|
|
74
|
-
/* @__PURE__ */ jsx("h2", { children: errorStatus }),
|
|
75
|
-
errorMessage && /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsx("pre", { children: errorMessage }) })
|
|
76
|
-
] }) }),
|
|
77
|
-
/* @__PURE__ */ jsx(ScrollRestoration, { nonce }),
|
|
78
|
-
/* @__PURE__ */ jsx(Scripts, { nonce })
|
|
79
|
-
] })
|
|
54
|
+
return /* @__PURE__ */ jsxs("div", { className: "route-error", children: [
|
|
55
|
+
/* @__PURE__ */ jsx("h1", { children: "Please report this error" }),
|
|
56
|
+
/* @__PURE__ */ jsx("h2", { children: errorStatus }),
|
|
57
|
+
errorMessage && /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsx("pre", { children: errorMessage }) })
|
|
80
58
|
] });
|
|
81
59
|
}
|
|
82
60
|
export {
|
|
83
61
|
ErrorBoundary,
|
|
84
|
-
|
|
62
|
+
Layout,
|
|
85
63
|
links
|
|
86
64
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
3
3
|
import { resolvePath, joinPath } from '@shopify/cli-kit/node/path';
|
|
4
|
-
import { collectLog, outputWarn } from '@shopify/cli-kit/node/output';
|
|
4
|
+
import { collectLog, outputInfo, outputContent, outputToken, outputWarn } from '@shopify/cli-kit/node/output';
|
|
5
5
|
import { removeFile, fileSize } from '@shopify/cli-kit/node/fs';
|
|
6
6
|
import { getPackageManager } from '@shopify/cli-kit/node/node-package-manager';
|
|
7
7
|
import { commonFlags, flagsToCamelObject } from '../../lib/flags.js';
|
|
@@ -10,6 +10,8 @@ import { hasViteConfig, getViteConfig } from '../../lib/vite-config.js';
|
|
|
10
10
|
import { checkLockfileStatus } from '../../lib/check-lockfile.js';
|
|
11
11
|
import { findMissingRoutes } from '../../lib/missing-routes.js';
|
|
12
12
|
import { runClassicCompilerBuild } from '../../lib/classic-compiler/build.js';
|
|
13
|
+
import { hydrogenBundleAnalyzer } from '../../lib/bundle/vite-plugin.js';
|
|
14
|
+
import { BUNDLE_ANALYZER_HTML_FILE, getBundleAnalysisSummary } from '../../lib/bundle/analyzer.js';
|
|
13
15
|
import { spawnCodegenProcess, codegen } from '../../lib/codegen.js';
|
|
14
16
|
import { isCI } from '../../lib/is-ci.js';
|
|
15
17
|
import { importVite } from '../../lib/import-utils.js';
|
|
@@ -33,8 +35,7 @@ class Build extends Command {
|
|
|
33
35
|
}),
|
|
34
36
|
// For the classic compiler:
|
|
35
37
|
"bundle-stats": Flags.boolean({
|
|
36
|
-
description: "
|
|
37
|
-
default: true,
|
|
38
|
+
description: "Show a bundle size summary after building. Defaults to true, use `--no-bundle-stats` to disable.",
|
|
38
39
|
allowNo: true
|
|
39
40
|
})
|
|
40
41
|
};
|
|
@@ -78,6 +79,7 @@ async function runBuild({
|
|
|
78
79
|
disableRouteWarning = false,
|
|
79
80
|
lockfileCheck = true,
|
|
80
81
|
assetPath = "/",
|
|
82
|
+
bundleStats = !isCI(),
|
|
81
83
|
watch = false,
|
|
82
84
|
onServerBuildStart,
|
|
83
85
|
onServerBuildFinish
|
|
@@ -129,8 +131,7 @@ async function runBuild({
|
|
|
129
131
|
clientBuildStatus = deferPromise();
|
|
130
132
|
},
|
|
131
133
|
buildEnd(error) {
|
|
132
|
-
if (error)
|
|
133
|
-
clientBuildStatus.reject(error);
|
|
134
|
+
if (error) clientBuildStatus.reject(error);
|
|
134
135
|
},
|
|
135
136
|
writeBundle() {
|
|
136
137
|
clientBuildStatus.resolve();
|
|
@@ -172,7 +173,22 @@ async function runBuild({
|
|
|
172
173
|
closeWatcher() {
|
|
173
174
|
this.error(new Error("Process exited before server build finished."));
|
|
174
175
|
}
|
|
175
|
-
}
|
|
176
|
+
},
|
|
177
|
+
...bundleStats ? [
|
|
178
|
+
hydrogenBundleAnalyzer({
|
|
179
|
+
minify: serverMinify ? (code, filepath) => vite.transformWithEsbuild(code, filepath, {
|
|
180
|
+
minify: true,
|
|
181
|
+
minifyWhitespace: true,
|
|
182
|
+
minifySyntax: true,
|
|
183
|
+
minifyIdentifiers: true,
|
|
184
|
+
sourcemap: false,
|
|
185
|
+
treeShaking: false,
|
|
186
|
+
// Tree-shaking would drop most exports in routes
|
|
187
|
+
legalComments: "none",
|
|
188
|
+
target: "esnext"
|
|
189
|
+
}).then((result) => result.code) : void 0
|
|
190
|
+
})
|
|
191
|
+
] : []
|
|
176
192
|
]
|
|
177
193
|
});
|
|
178
194
|
if (!watch) {
|
|
@@ -189,6 +205,15 @@ async function runBuild({
|
|
|
189
205
|
};
|
|
190
206
|
const codegenProcess = useCodegen ? watch ? spawnCodegenProcess(codegenOptions) : await codegen(codegenOptions).then(() => void 0) : void 0;
|
|
191
207
|
if (!watch && process.env.NODE_ENV !== "development") {
|
|
208
|
+
if (bundleStats) {
|
|
209
|
+
const bundleAnalysisPath = "file://" + joinPath(serverOutDir, BUNDLE_ANALYZER_HTML_FILE);
|
|
210
|
+
outputInfo(
|
|
211
|
+
outputContent`${await getBundleAnalysisSummary(serverOutDir) || "\n"}\n │\n └─── ${outputToken.link(
|
|
212
|
+
"Complete analysis: " + bundleAnalysisPath,
|
|
213
|
+
bundleAnalysisPath
|
|
214
|
+
)}\n\n`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
192
217
|
const sizeMB = await fileSize(serverOutFile) / (1024 * 1024);
|
|
193
218
|
if (sizeMB >= WORKER_BUILD_SIZE_LIMIT) {
|
|
194
219
|
outputWarn(
|
|
@@ -216,10 +241,8 @@ This build is missing ${missingRoutes.length} route${missingRoutes.length > 1 ?
|
|
|
216
241
|
codegenProcess?.removeAllListeners("close");
|
|
217
242
|
codegenProcess?.kill("SIGINT");
|
|
218
243
|
const promises = [];
|
|
219
|
-
if ("close" in clientBuild)
|
|
220
|
-
|
|
221
|
-
if ("close" in serverBuild)
|
|
222
|
-
promises.push(serverBuild.close());
|
|
244
|
+
if ("close" in clientBuild) promises.push(clientBuild.close());
|
|
245
|
+
if ("close" in serverBuild) promises.push(serverBuild.close());
|
|
223
246
|
await Promise.allSettled(promises);
|
|
224
247
|
if (clientBuildStatus?.state === "pending" || serverBuildStatus?.state === "pending") {
|
|
225
248
|
clientBuildStatus?.promise.catch(() => {
|
|
@@ -134,8 +134,7 @@ async function runCustomerAccountPush({
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
async function cleanupCustomerApplicationUrls(session, storefrontId, customerAccountConfig = {}) {
|
|
137
|
-
if (!Object.values(customerAccountConfig).some(Boolean))
|
|
138
|
-
return;
|
|
137
|
+
if (!Object.values(customerAccountConfig).some(Boolean)) return;
|
|
139
138
|
outputDebug(
|
|
140
139
|
`Cleaning up Customer Application url "${customerAccountConfig.redirectUri}"`
|
|
141
140
|
);
|
|
@@ -151,11 +150,9 @@ ${error?.message}`
|
|
|
151
150
|
});
|
|
152
151
|
}
|
|
153
152
|
async function getStorefrontId(root, storefrontIdFromFlag) {
|
|
154
|
-
if (storefrontIdFromFlag)
|
|
155
|
-
return storefrontIdFromFlag;
|
|
153
|
+
if (storefrontIdFromFlag) return storefrontIdFromFlag;
|
|
156
154
|
const { session, config } = await login(root);
|
|
157
|
-
if (config.storefront?.id)
|
|
158
|
-
return config.storefront.id;
|
|
155
|
+
if (config.storefront?.id) return config.storefront.id;
|
|
159
156
|
const cliCommand = await getCliCommand();
|
|
160
157
|
const linkedStore = await linkStorefront(root, session, config, {
|
|
161
158
|
cliCommand
|
|
@@ -34,7 +34,7 @@ class DebugCpu extends Command {
|
|
|
34
34
|
async run() {
|
|
35
35
|
const { flags } = await this.parse(DebugCpu);
|
|
36
36
|
const originalDirectory = flags.path ? resolvePath(flags.path) : process.cwd();
|
|
37
|
-
const diff = flags.
|
|
37
|
+
const diff = flags.diff ? await prepareDiffDirectory(originalDirectory, true) : void 0;
|
|
38
38
|
const { close } = await runDebugCpu({
|
|
39
39
|
...flagsToCamelObject(flags),
|
|
40
40
|
directory: diff?.targetDirectory ?? originalDirectory,
|
|
@@ -47,8 +47,7 @@ class DebugCpu extends Command {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
async function runDebugCpu({ directory, entry, output }) {
|
|
50
|
-
if (!process.env.NODE_ENV)
|
|
51
|
-
process.env.NODE_ENV = "production";
|
|
50
|
+
if (!process.env.NODE_ENV) process.env.NODE_ENV = "production";
|
|
52
51
|
muteDevLogs({ workerReload: false });
|
|
53
52
|
let { buildPath, buildPathWorkerFile } = getProjectPaths(directory);
|
|
54
53
|
const isClassicProject = await hasRemixConfigFile(directory);
|
|
@@ -99,6 +98,7 @@ Waiting for changes...`);
|
|
|
99
98
|
sourcemap: true,
|
|
100
99
|
disableRouteWarning: true,
|
|
101
100
|
lockfileCheck: false,
|
|
101
|
+
bundleStats: false,
|
|
102
102
|
...hooks,
|
|
103
103
|
onServerBuildStart() {
|
|
104
104
|
if (times === 0) {
|