@shopify/cli-hydrogen 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/hydrogen/build.js +3 -8
- package/dist/commands/hydrogen/deploy.js +79 -32
- package/dist/commands/hydrogen/deploy.test.js +162 -5
- package/dist/commands/hydrogen/generate/route.js +6 -1
- package/dist/commands/hydrogen/init.test.js +2 -1
- package/dist/commands/hydrogen/setup.js +17 -19
- package/dist/generator-templates/starter/CHANGELOG.md +45 -0
- package/dist/generator-templates/starter/README.md +25 -2
- package/dist/generator-templates/starter/app/components/Cart.tsx +2 -2
- package/dist/generator-templates/starter/app/components/Layout.tsx +9 -1
- package/dist/generator-templates/starter/app/components/Search.tsx +44 -15
- package/dist/generator-templates/starter/app/lib/search.ts +29 -0
- package/dist/generator-templates/starter/app/root.tsx +0 -2
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +2 -2
- package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +1 -21
- package/dist/generator-templates/starter/app/routes/cart.tsx +1 -5
- package/dist/generator-templates/starter/app/routes/search.tsx +8 -2
- package/dist/generator-templates/starter/app/styles/app.css +10 -15
- package/dist/generator-templates/starter/package.json +7 -7
- package/dist/generator-templates/starter/remix.config.js +1 -0
- package/dist/generator-templates/starter/remix.env.d.ts +6 -2
- package/dist/generator-templates/starter/server.ts +1 -0
- package/dist/hooks/init.js +3 -3
- package/dist/lib/codegen.js +1 -8
- package/dist/lib/file.js +4 -1
- package/dist/lib/flags.js +6 -0
- package/dist/lib/graphiql-url.js +3 -0
- package/dist/lib/mini-oxygen/assets.js +17 -1
- package/dist/lib/onboarding/common.js +4 -3
- package/dist/lib/onboarding/local.js +7 -7
- package/dist/lib/onboarding/remote.js +2 -1
- package/dist/lib/setups/i18n/replacers.test.js +3 -2
- package/dist/lib/setups/routes/generate.js +58 -10
- package/dist/lib/setups/routes/templates/locale-check.js +9 -0
- package/dist/lib/setups/routes/templates/locale-check.ts +16 -0
- package/dist/lib/shell.js +1 -1
- package/dist/lib/template-diff.js +13 -3
- package/dist/virtual-routes/components/RequestDetails.jsx +2 -2
- package/oclif.manifest.json +47 -8
- package/package.json +5 -5
|
@@ -15,7 +15,7 @@ export function CartMain({layout, cart}: CartMainProps) {
|
|
|
15
15
|
const linesCount = Boolean(cart?.lines?.nodes?.length || 0);
|
|
16
16
|
const withDiscount =
|
|
17
17
|
cart &&
|
|
18
|
-
Boolean(cart
|
|
18
|
+
Boolean(cart?.discountCodes?.filter((code) => code.applicable)?.length);
|
|
19
19
|
const className = `cart-main ${withDiscount ? 'with-discount' : ''}`;
|
|
20
20
|
|
|
21
21
|
return (
|
|
@@ -179,7 +179,7 @@ function CartLineQuantity({line}: {line: CartLine}) {
|
|
|
179
179
|
const nextQuantity = Number((quantity + 1).toFixed(0));
|
|
180
180
|
|
|
181
181
|
return (
|
|
182
|
-
<div className="cart-line-
|
|
182
|
+
<div className="cart-line-quantity">
|
|
183
183
|
<small>Quantity: {quantity} </small>
|
|
184
184
|
<CartLineUpdateButton lines={[{id: lineId, quantity: prevQuantity}]}>
|
|
185
185
|
<button
|
|
@@ -76,7 +76,15 @@ function SearchAside() {
|
|
|
76
76
|
type="search"
|
|
77
77
|
/>
|
|
78
78
|
|
|
79
|
-
<button
|
|
79
|
+
<button
|
|
80
|
+
onClick={() => {
|
|
81
|
+
window.location.href = inputRef?.current?.value
|
|
82
|
+
? `/search?q=${inputRef.current.value}`
|
|
83
|
+
: `/search`;
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
86
|
+
Search
|
|
87
|
+
</button>
|
|
80
88
|
</div>
|
|
81
89
|
)}
|
|
82
90
|
</PredictiveSearchForm>
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
Form,
|
|
4
4
|
useParams,
|
|
5
5
|
useFetcher,
|
|
6
|
-
useFetchers,
|
|
7
6
|
type FormProps,
|
|
8
7
|
} from '@remix-run/react';
|
|
9
8
|
import {Image, Money, Pagination} from '@shopify/hydrogen';
|
|
10
9
|
import React, {useRef, useEffect} from 'react';
|
|
10
|
+
import {applyTrackingParams} from '~/lib/search';
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
13
|
PredictiveProductFragment,
|
|
@@ -104,7 +104,10 @@ export function SearchForm({searchTerm}: {searchTerm: string}) {
|
|
|
104
104
|
|
|
105
105
|
export function SearchResults({
|
|
106
106
|
results,
|
|
107
|
-
|
|
107
|
+
searchTerm,
|
|
108
|
+
}: Pick<FetchSearchResultsReturn['searchResults'], 'results'> & {
|
|
109
|
+
searchTerm: string;
|
|
110
|
+
}) {
|
|
108
111
|
if (!results) {
|
|
109
112
|
return null;
|
|
110
113
|
}
|
|
@@ -128,6 +131,7 @@ export function SearchResults({
|
|
|
128
131
|
<SearchResultsProductsGrid
|
|
129
132
|
key="products"
|
|
130
133
|
products={productResults}
|
|
134
|
+
searchTerm={searchTerm}
|
|
131
135
|
/>
|
|
132
136
|
) : null;
|
|
133
137
|
}
|
|
@@ -148,19 +152,44 @@ export function SearchResults({
|
|
|
148
152
|
);
|
|
149
153
|
}
|
|
150
154
|
|
|
151
|
-
function SearchResultsProductsGrid({
|
|
155
|
+
function SearchResultsProductsGrid({
|
|
156
|
+
products,
|
|
157
|
+
searchTerm,
|
|
158
|
+
}: Pick<SearchQuery, 'products'> & {searchTerm: string}) {
|
|
152
159
|
return (
|
|
153
160
|
<div className="search-result">
|
|
154
161
|
<h2>Products</h2>
|
|
155
162
|
<Pagination connection={products}>
|
|
156
163
|
{({nodes, isLoading, NextLink, PreviousLink}) => {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
const ItemsMarkup = nodes.map((product) => {
|
|
165
|
+
const trackingParams = applyTrackingParams(
|
|
166
|
+
product,
|
|
167
|
+
`q=${encodeURIComponent(searchTerm)}`,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div className="search-results-item" key={product.id}>
|
|
172
|
+
<Link
|
|
173
|
+
prefetch="intent"
|
|
174
|
+
to={`/products/${product.handle}${trackingParams}`}
|
|
175
|
+
>
|
|
176
|
+
{product.variants.nodes[0].image && (
|
|
177
|
+
<Image
|
|
178
|
+
data={product.variants.nodes[0].image}
|
|
179
|
+
alt={product.title}
|
|
180
|
+
width={50}
|
|
181
|
+
/>
|
|
182
|
+
)}
|
|
183
|
+
<div>
|
|
184
|
+
<p>{product.title}</p>
|
|
185
|
+
<small>
|
|
186
|
+
<Money data={product.variants.nodes[0].price} />
|
|
187
|
+
</small>
|
|
188
|
+
</div>
|
|
189
|
+
</Link>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
});
|
|
164
193
|
return (
|
|
165
194
|
<div>
|
|
166
195
|
<div>
|
|
@@ -169,7 +198,7 @@ function SearchResultsProductsGrid({products}: Pick<SearchQuery, 'products'>) {
|
|
|
169
198
|
</PreviousLink>
|
|
170
199
|
</div>
|
|
171
200
|
<div>
|
|
172
|
-
{
|
|
201
|
+
{ItemsMarkup}
|
|
173
202
|
<br />
|
|
174
203
|
</div>
|
|
175
204
|
<div>
|
|
@@ -251,7 +280,9 @@ export function PredictiveSearchForm({
|
|
|
251
280
|
...props
|
|
252
281
|
}: SearchFromProps) {
|
|
253
282
|
const params = useParams();
|
|
254
|
-
const fetcher = useFetcher<NormalizedPredictiveSearchResults>(
|
|
283
|
+
const fetcher = useFetcher<NormalizedPredictiveSearchResults>({
|
|
284
|
+
key: 'search',
|
|
285
|
+
});
|
|
255
286
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
256
287
|
|
|
257
288
|
function fetchResults(event: React.ChangeEvent<HTMLInputElement>) {
|
|
@@ -318,7 +349,6 @@ export function PredictiveSearchResults() {
|
|
|
318
349
|
/>
|
|
319
350
|
))}
|
|
320
351
|
</div>
|
|
321
|
-
{/* view all results /search?q=term */}
|
|
322
352
|
{searchTerm.current && (
|
|
323
353
|
<Link onClick={goToSearchResult} to={`/search?q=${searchTerm.current}`}>
|
|
324
354
|
<p>
|
|
@@ -425,10 +455,9 @@ type UseSearchReturn = NormalizedPredictiveSearch & {
|
|
|
425
455
|
};
|
|
426
456
|
|
|
427
457
|
function usePredictiveSearch(): UseSearchReturn {
|
|
428
|
-
const
|
|
458
|
+
const searchFetcher = useFetcher<FetchSearchResultsReturn>({key: 'search'});
|
|
429
459
|
const searchTerm = useRef<string>('');
|
|
430
460
|
const searchInputRef = useRef<HTMLInputElement | null>(null);
|
|
431
|
-
const searchFetcher = fetchers.find((fetcher) => fetcher.data?.searchResults);
|
|
432
461
|
|
|
433
462
|
if (searchFetcher?.state === 'loading') {
|
|
434
463
|
searchTerm.current = (searchFetcher.formData?.get('q') || '') as string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PredictiveQueryFragment,
|
|
3
|
+
SearchProductFragment,
|
|
4
|
+
PredictiveProductFragment,
|
|
5
|
+
PredictiveCollectionFragment,
|
|
6
|
+
PredictivePageFragment,
|
|
7
|
+
PredictiveArticleFragment,
|
|
8
|
+
} from 'storefrontapi.generated';
|
|
9
|
+
|
|
10
|
+
export function applyTrackingParams(
|
|
11
|
+
resource:
|
|
12
|
+
| PredictiveQueryFragment
|
|
13
|
+
| SearchProductFragment
|
|
14
|
+
| PredictiveProductFragment
|
|
15
|
+
| PredictiveCollectionFragment
|
|
16
|
+
| PredictiveArticleFragment
|
|
17
|
+
| PredictivePageFragment,
|
|
18
|
+
params?: string,
|
|
19
|
+
) {
|
|
20
|
+
if (params) {
|
|
21
|
+
return resource?.trackingParameters
|
|
22
|
+
? `?${params}&${resource.trackingParameters}`
|
|
23
|
+
: `?${params}`;
|
|
24
|
+
} else {
|
|
25
|
+
return resource?.trackingParameters
|
|
26
|
+
? `?${resource.trackingParameters}`
|
|
27
|
+
: '';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -73,8 +73,6 @@ export async function loader({context}: LoaderFunctionArgs) {
|
|
|
73
73
|
const publicStoreDomain = context.env.PUBLIC_STORE_DOMAIN;
|
|
74
74
|
|
|
75
75
|
const isLoggedInPromise = customerAccount.isLoggedIn();
|
|
76
|
-
|
|
77
|
-
// defer the cart query by not awaiting it
|
|
78
76
|
const cartPromise = cart.get();
|
|
79
77
|
|
|
80
78
|
// defer the footer query (below the fold)
|
|
@@ -95,7 +95,7 @@ function EmptyOrders() {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
function OrderItem({order}: {order: OrderItemFragment}) {
|
|
98
|
-
const fulfillmentStatus = flattenConnection(order.fulfillments)[0]
|
|
98
|
+
const fulfillmentStatus = flattenConnection(order.fulfillments)[0]?.status;
|
|
99
99
|
return (
|
|
100
100
|
<>
|
|
101
101
|
<fieldset>
|
|
@@ -104,7 +104,7 @@ function OrderItem({order}: {order: OrderItemFragment}) {
|
|
|
104
104
|
</Link>
|
|
105
105
|
<p>{new Date(order.processedAt).toDateString()}</p>
|
|
106
106
|
<p>{order.financialStatus}</p>
|
|
107
|
-
<p>{fulfillmentStatus}</p>
|
|
107
|
+
{fulfillmentStatus && <p>{fulfillmentStatus}</p>}
|
|
108
108
|
<Money data={order.totalPrice} />
|
|
109
109
|
<Link to={`/account/orders/${btoa(order.id)}`}>View Order →</Link>
|
|
110
110
|
</fieldset>
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
NormalizedPredictiveSearchResults,
|
|
5
5
|
} from '~/components/Search';
|
|
6
6
|
import {NO_PREDICTIVE_SEARCH_RESULTS} from '~/components/Search';
|
|
7
|
+
import {applyTrackingParams} from '~/lib/search';
|
|
7
8
|
|
|
8
9
|
import type {
|
|
9
10
|
PredictiveArticleFragment,
|
|
@@ -14,12 +15,6 @@ import type {
|
|
|
14
15
|
PredictiveSearchQuery,
|
|
15
16
|
} from 'storefrontapi.generated';
|
|
16
17
|
|
|
17
|
-
type PredictiveSearchResultItem =
|
|
18
|
-
| PredictiveArticleFragment
|
|
19
|
-
| PredictiveCollectionFragment
|
|
20
|
-
| PredictivePageFragment
|
|
21
|
-
| PredictiveProductFragment;
|
|
22
|
-
|
|
23
18
|
type PredictiveSearchTypes =
|
|
24
19
|
| 'ARTICLE'
|
|
25
20
|
| 'COLLECTION'
|
|
@@ -121,21 +116,6 @@ export function normalizePredictiveSearchResults(
|
|
|
121
116
|
};
|
|
122
117
|
}
|
|
123
118
|
|
|
124
|
-
function applyTrackingParams(
|
|
125
|
-
resource: PredictiveSearchResultItem | PredictiveQueryFragment,
|
|
126
|
-
params?: string,
|
|
127
|
-
) {
|
|
128
|
-
if (params) {
|
|
129
|
-
return resource.trackingParameters
|
|
130
|
-
? `?${params}&${resource.trackingParameters}`
|
|
131
|
-
: `?${params}`;
|
|
132
|
-
} else {
|
|
133
|
-
return resource.trackingParameters
|
|
134
|
-
? `?${resource.trackingParameters}`
|
|
135
|
-
: '';
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
119
|
const localePrefix = locale ? `/${locale}` : '';
|
|
140
120
|
const results: NormalizedPredictiveSearchResults = [];
|
|
141
121
|
|
|
@@ -13,10 +13,7 @@ export const meta: MetaFunction = () => {
|
|
|
13
13
|
export async function action({request, context}: ActionFunctionArgs) {
|
|
14
14
|
const {cart} = context;
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
request.formData(),
|
|
18
|
-
await context.customerAccount.getAccessToken(),
|
|
19
|
-
]);
|
|
16
|
+
const formData = await request.formData();
|
|
20
17
|
|
|
21
18
|
const {action, inputs} = CartForm.getFormInput(formData);
|
|
22
19
|
|
|
@@ -54,7 +51,6 @@ export async function action({request, context}: ActionFunctionArgs) {
|
|
|
54
51
|
case CartForm.ACTIONS.BuyerIdentityUpdate: {
|
|
55
52
|
result = await cart.updateBuyerIdentity({
|
|
56
53
|
...inputs.buyerIdentity,
|
|
57
|
-
customerAccessToken,
|
|
58
54
|
});
|
|
59
55
|
break;
|
|
60
56
|
}
|
|
@@ -41,7 +41,10 @@ export async function loader({request, context}: LoaderFunctionArgs) {
|
|
|
41
41
|
totalResults,
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
return defer({
|
|
44
|
+
return defer({
|
|
45
|
+
searchTerm,
|
|
46
|
+
searchResults,
|
|
47
|
+
});
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export default function SearchPage() {
|
|
@@ -54,7 +57,10 @@ export default function SearchPage() {
|
|
|
54
57
|
{!searchTerm || !searchResults.totalResults ? (
|
|
55
58
|
<NoSearchResults />
|
|
56
59
|
) : (
|
|
57
|
-
<SearchResults
|
|
60
|
+
<SearchResults
|
|
61
|
+
results={searchResults.results}
|
|
62
|
+
searchTerm={searchTerm}
|
|
63
|
+
/>
|
|
58
64
|
)}
|
|
59
65
|
</div>
|
|
60
66
|
);
|
|
@@ -181,11 +181,6 @@ aside li {
|
|
|
181
181
|
margin-top: auto;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
.footer-menu-missing {
|
|
185
|
-
display: inline-block;
|
|
186
|
-
margin: 1rem;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
184
|
.footer-menu {
|
|
190
185
|
align-items: center;
|
|
191
186
|
display: flex;
|
|
@@ -237,7 +232,7 @@ aside li {
|
|
|
237
232
|
width: calc(var(--aside-width) - 40px);
|
|
238
233
|
}
|
|
239
234
|
|
|
240
|
-
.cart-line-
|
|
235
|
+
.cart-line-quantity {
|
|
241
236
|
display: flex;
|
|
242
237
|
}
|
|
243
238
|
|
|
@@ -297,6 +292,15 @@ aside li {
|
|
|
297
292
|
margin-bottom: 0.5rem;
|
|
298
293
|
}
|
|
299
294
|
|
|
295
|
+
.search-results-item a {
|
|
296
|
+
display: flex;
|
|
297
|
+
flex: row;
|
|
298
|
+
align-items: center;
|
|
299
|
+
gap: 1rem;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
300
304
|
/*
|
|
301
305
|
* --------------------------------------------------
|
|
302
306
|
* routes/__index
|
|
@@ -392,11 +396,6 @@ aside li {
|
|
|
392
396
|
margin-top: 0;
|
|
393
397
|
}
|
|
394
398
|
|
|
395
|
-
.product-images {
|
|
396
|
-
display: grid;
|
|
397
|
-
grid-gap: 1rem;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
399
|
.product-image img {
|
|
401
400
|
height: auto;
|
|
402
401
|
width: 100%;
|
|
@@ -463,10 +462,6 @@ aside li {
|
|
|
463
462
|
* routes/account
|
|
464
463
|
* --------------------------------------------------
|
|
465
464
|
*/
|
|
466
|
-
.account-profile-marketing {
|
|
467
|
-
display: flex;
|
|
468
|
-
align-items: center;
|
|
469
|
-
}
|
|
470
465
|
|
|
471
466
|
.account-logout {
|
|
472
467
|
display: inline-block;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "skeleton",
|
|
3
3
|
"private": true,
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.4",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "shopify hydrogen build",
|
|
8
8
|
"dev": "shopify hydrogen dev --codegen",
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
},
|
|
14
14
|
"prettier": "@shopify/prettier-config",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@remix-run/react": "^2.
|
|
17
|
-
"@remix-run/server-runtime": "^2.
|
|
16
|
+
"@remix-run/react": "^2.6.0",
|
|
17
|
+
"@remix-run/server-runtime": "^2.6.0",
|
|
18
18
|
"@shopify/cli": "3.52.0",
|
|
19
|
-
"@shopify/cli-hydrogen": "^7.
|
|
20
|
-
"@shopify/hydrogen": "~2024.1.
|
|
19
|
+
"@shopify/cli-hydrogen": "^7.1.0",
|
|
20
|
+
"@shopify/hydrogen": "~2024.1.2",
|
|
21
21
|
"@shopify/remix-oxygen": "^2.0.3",
|
|
22
22
|
"graphql": "^16.6.0",
|
|
23
23
|
"graphql-tag": "^2.12.6",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"react-dom": "^18.2.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@remix-run/dev": "^2.
|
|
30
|
-
"@remix-run/eslint-config": "^2.
|
|
29
|
+
"@remix-run/dev": "^2.6.0",
|
|
30
|
+
"@remix-run/eslint-config": "^2.6.0",
|
|
31
31
|
"@shopify/oxygen-workers-types": "^4.0.0",
|
|
32
32
|
"@shopify/prettier-config": "^1.1.2",
|
|
33
33
|
"@total-typescript/ts-reset": "^0.4.2",
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
// Enhance TypeScript's built-in typings.
|
|
6
6
|
import '@total-typescript/ts-reset';
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
Storefront,
|
|
10
|
+
CustomerAccount,
|
|
11
|
+
HydrogenCart,
|
|
12
|
+
} from '@shopify/hydrogen';
|
|
9
13
|
import type {AppSession} from '~/lib/session';
|
|
10
14
|
|
|
11
15
|
declare global {
|
|
@@ -36,7 +40,7 @@ declare module '@shopify/remix-oxygen' {
|
|
|
36
40
|
env: Env;
|
|
37
41
|
cart: HydrogenCart;
|
|
38
42
|
storefront: Storefront;
|
|
39
|
-
customerAccount:
|
|
43
|
+
customerAccount: CustomerAccount;
|
|
40
44
|
session: AppSession;
|
|
41
45
|
waitUntil: ExecutionContext['waitUntil'];
|
|
42
46
|
}
|
package/dist/hooks/init.js
CHANGED
|
@@ -3,7 +3,7 @@ import { outputDebug } from '@shopify/cli-kit/node/output';
|
|
|
3
3
|
|
|
4
4
|
const EXPERIMENTAL_VM_MODULES_FLAG = "--experimental-vm-modules";
|
|
5
5
|
function commandNeedsVM(id = "", argv = []) {
|
|
6
|
-
return "hydrogen:debug:cpu";
|
|
6
|
+
return id === "hydrogen:debug:cpu" || ["hydrogen:dev", "hydrogen:preview"].includes(id) && argv.includes("--legacy-runtime");
|
|
7
7
|
}
|
|
8
8
|
const hook = async function(options) {
|
|
9
9
|
if (commandNeedsVM(options.id, options.argv) && !process.execArgv.includes(EXPERIMENTAL_VM_MODULES_FLAG) && !(process.env.NODE_OPTIONS ?? "").includes(EXPERIMENTAL_VM_MODULES_FLAG)) {
|
|
@@ -12,8 +12,8 @@ const hook = async function(options) {
|
|
|
12
12
|
);
|
|
13
13
|
const [command, ...args] = process.argv;
|
|
14
14
|
args.unshift(EXPERIMENTAL_VM_MODULES_FLAG);
|
|
15
|
-
spawnSync(command, args, { stdio: "inherit" });
|
|
16
|
-
process.exit(
|
|
15
|
+
const result = spawnSync(command, args, { stdio: "inherit" });
|
|
16
|
+
process.exit(result.status ?? 1);
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
var init_default = hook;
|
package/dist/lib/codegen.js
CHANGED
|
@@ -63,14 +63,7 @@ function spawnCodegenProcess({
|
|
|
63
63
|
});
|
|
64
64
|
return child;
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
await import('@shopify/hydrogen-codegen/patch').catch((error) => {
|
|
68
|
-
throw new AbortError(
|
|
69
|
-
`Failed to patch dependencies for codegen.
|
|
70
|
-
${error.stack}`,
|
|
71
|
-
"Please report this issue."
|
|
72
|
-
);
|
|
73
|
-
});
|
|
66
|
+
function codegen(options) {
|
|
74
67
|
return generateTypes(options).catch((error) => {
|
|
75
68
|
const { message, details } = normalizeCodegenError(
|
|
76
69
|
error.message,
|
package/dist/lib/file.js
CHANGED
|
@@ -84,7 +84,10 @@ async function mergePackageJson(sourceDir, targetDir, options) {
|
|
|
84
84
|
}, {});
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
await writePackageJSON(
|
|
87
|
+
await writePackageJSON(
|
|
88
|
+
targetDir,
|
|
89
|
+
options?.onResult?.(targetPkgJson) ?? targetPkgJson
|
|
90
|
+
);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
export { findFileWithExtension, mergePackageJson, replaceFileContent };
|
package/dist/lib/flags.js
CHANGED
|
@@ -92,6 +92,12 @@ const commonFlags = {
|
|
|
92
92
|
description: "Applies the current files on top of Hydrogen's starter template in a temporary directory.",
|
|
93
93
|
default: false,
|
|
94
94
|
required: false
|
|
95
|
+
}),
|
|
96
|
+
lockfileCheck: Flags.boolean({
|
|
97
|
+
allowNo: true,
|
|
98
|
+
default: true,
|
|
99
|
+
description: "Checks that there is exactly 1 valid lockfile in the project. Defaults to true, use `--no-lockfile-check` to disable.",
|
|
100
|
+
env: "SHOPIFY_HYDROGEN_FLAG_LOCKFILE_CHECK"
|
|
95
101
|
})
|
|
96
102
|
};
|
|
97
103
|
function flagsToCamelObject(obj) {
|
package/dist/lib/graphiql-url.js
CHANGED
|
@@ -8,6 +8,9 @@ function getGraphiQLUrl({
|
|
|
8
8
|
if (typeof variables !== "string")
|
|
9
9
|
variables = JSON.stringify(variables);
|
|
10
10
|
url += `?query=${encodeURIComponent(query)}${variables ? `&variables=${encodeURIComponent(variables)}` : ""}`;
|
|
11
|
+
if (graphql.schema) {
|
|
12
|
+
url += `&schema=${graphql.schema}`;
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
return url;
|
|
13
16
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
3
4
|
import { createServer } from 'node:http';
|
|
4
5
|
import { lookupMimeType } from '@shopify/cli-kit/node/mimes';
|
|
5
6
|
|
|
@@ -10,13 +11,28 @@ function buildAssetsUrl(assetsPort) {
|
|
|
10
11
|
}
|
|
11
12
|
function createAssetsServer(buildPathClient) {
|
|
12
13
|
return createServer(async (req, res) => {
|
|
14
|
+
if (req.method === "OPTIONS") {
|
|
15
|
+
res.setHeader("Access-Control-Allow-Origin", req.headers.origin || "*");
|
|
16
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
17
|
+
res.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
18
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
19
|
+
res.writeHead(204);
|
|
20
|
+
res.end();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
13
23
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
14
24
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
15
25
|
const pathname = req.url?.split("?")[0] || "";
|
|
16
26
|
const isValidAssetPath = pathname.startsWith(`/${artificialAssetPrefix}/`) && !pathname.includes("..");
|
|
17
27
|
const relativeAssetPath = isValidAssetPath ? pathname.replace(`/${artificialAssetPrefix}`, "") : pathname;
|
|
18
28
|
if (isValidAssetPath) {
|
|
19
|
-
|
|
29
|
+
let filePath = path.join(buildPathClient, relativeAssetPath);
|
|
30
|
+
if (relativeAssetPath === "/graphiql/customer-account.schema.json") {
|
|
31
|
+
const require2 = createRequire(import.meta.url);
|
|
32
|
+
filePath = require2.resolve(
|
|
33
|
+
"@shopify/hydrogen/customer-account.schema.json"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
20
36
|
const file = await fs.open(filePath).catch(() => {
|
|
21
37
|
});
|
|
22
38
|
const stat = await file?.stat().catch(() => {
|
|
@@ -11,7 +11,7 @@ import colors from '@shopify/cli-kit/node/colors';
|
|
|
11
11
|
import { login, renderLoginSuccess } from '../auth.js';
|
|
12
12
|
import { renderI18nPrompt, setupI18nStrategy, I18N_STRATEGY_NAME_MAP } from '../setups/i18n/index.js';
|
|
13
13
|
import { titleize } from '../string.js';
|
|
14
|
-
import { ALIAS_NAME, createPlatformShortcut
|
|
14
|
+
import { ALIAS_NAME, createPlatformShortcut } from '../shell.js';
|
|
15
15
|
import { transpileProject } from '../transpile/index.js';
|
|
16
16
|
import { renderCssPrompt, setupCssStrategy, CSS_STRATEGY_NAME_MAP } from '../setups/css/index.js';
|
|
17
17
|
import { renderRoutePrompt, generateRoutes, generateProjectFile } from '../setups/routes/generate.js';
|
|
@@ -75,6 +75,8 @@ function generateProjectEntries(options) {
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
async function handleCliShortcut(controller, cliCommand, flagShortcut) {
|
|
78
|
+
if (cliCommand === ALIAS_NAME)
|
|
79
|
+
return {};
|
|
78
80
|
const shouldCreateShortcut = flagShortcut ?? await renderConfirmationPrompt({
|
|
79
81
|
confirmationMessage: "Yes",
|
|
80
82
|
cancellationMessage: "No",
|
|
@@ -329,7 +331,7 @@ async function renderProjectReady(project, {
|
|
|
329
331
|
packageManager,
|
|
330
332
|
depsInstalled,
|
|
331
333
|
cssStrategy,
|
|
332
|
-
|
|
334
|
+
cliCommand,
|
|
333
335
|
routes,
|
|
334
336
|
i18n,
|
|
335
337
|
depsError,
|
|
@@ -369,7 +371,6 @@ async function renderProjectReady(project, {
|
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
373
|
const padMin = 1 + bodyLines.reduce((max, [label]) => Math.max(max, label.length), 0);
|
|
372
|
-
const cliCommand = hasCreatedShortcut ? ALIAS_NAME : await getCliCommand(project.directory, packageManager);
|
|
373
374
|
const render = hasErrors ? renderWarning : renderSuccess;
|
|
374
375
|
render({
|
|
375
376
|
headline: `Storefront setup complete` + (hasErrors ? " with errors (see warnings below)." : "!"),
|
|
@@ -156,7 +156,7 @@ async function setupLocalStarterTemplate(options, controller) {
|
|
|
156
156
|
packageManager,
|
|
157
157
|
cssStrategy,
|
|
158
158
|
depsInstalled: false,
|
|
159
|
-
|
|
159
|
+
cliCommand: await getCliCommand("", packageManager)
|
|
160
160
|
};
|
|
161
161
|
if (shouldInstallDeps) {
|
|
162
162
|
const installingDepsPromise = backgroundWorkPromise.then(async () => {
|
|
@@ -174,19 +174,19 @@ async function setupLocalStarterTemplate(options, controller) {
|
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
176
|
}
|
|
177
|
-
const pkgManagerCommand = await getCliCommand("", packageManager);
|
|
178
177
|
const { createShortcut, showShortcutBanner } = await handleCliShortcut(
|
|
179
178
|
controller,
|
|
180
|
-
|
|
179
|
+
setupSummary.cliCommand,
|
|
181
180
|
options.shortcut
|
|
182
181
|
);
|
|
183
182
|
if (createShortcut) {
|
|
184
183
|
backgroundWorkPromise = backgroundWorkPromise.then(async () => {
|
|
185
|
-
|
|
184
|
+
if (await createShortcut()) {
|
|
185
|
+
setupSummary.cliCommand = ALIAS_NAME;
|
|
186
|
+
}
|
|
186
187
|
});
|
|
187
188
|
showShortcutBanner();
|
|
188
189
|
}
|
|
189
|
-
const cliCommand = createShortcut ? ALIAS_NAME : pkgManagerCommand;
|
|
190
190
|
renderSuccess({
|
|
191
191
|
headline: [
|
|
192
192
|
{ userInput: storefrontInfo?.title ?? project.name },
|
|
@@ -196,13 +196,13 @@ async function setupLocalStarterTemplate(options, controller) {
|
|
|
196
196
|
const continueWithSetup = (options.i18n ?? options.routes) !== void 0 || await renderConfirmationPrompt({
|
|
197
197
|
message: "Do you want to scaffold routes and core functionality?",
|
|
198
198
|
confirmationMessage: "Yes, set up now",
|
|
199
|
-
cancellationMessage: "No, set up later " + colors.dim(`(run \`${cliCommand} setup\`)`),
|
|
199
|
+
cancellationMessage: "No, set up later " + colors.dim(`(run \`${setupSummary.cliCommand} setup\`)`),
|
|
200
200
|
abortSignal: controller.signal
|
|
201
201
|
});
|
|
202
202
|
if (continueWithSetup) {
|
|
203
203
|
const { i18nStrategy, setupI18n } = await handleI18n(
|
|
204
204
|
controller,
|
|
205
|
-
cliCommand,
|
|
205
|
+
setupSummary.cliCommand,
|
|
206
206
|
options.i18n
|
|
207
207
|
);
|
|
208
208
|
const { setupRoutes } = await handleRouteGeneration(
|
|
@@ -5,6 +5,7 @@ import { joinPath } from '@shopify/cli-kit/node/path';
|
|
|
5
5
|
import { renderTasks, renderInfo } from '@shopify/cli-kit/node/ui';
|
|
6
6
|
import { getLatestTemplates } from '../template-downloader.js';
|
|
7
7
|
import { applyTemplateDiff } from '../template-diff.js';
|
|
8
|
+
import { getCliCommand } from '../shell.js';
|
|
8
9
|
import { createAbortHandler, handleProjectLocation, handleLanguage, createInitialCommit, handleDependencies, commitAll, renderProjectReady } from './common.js';
|
|
9
10
|
|
|
10
11
|
async function setupRemoteTemplate(options, controller) {
|
|
@@ -65,7 +66,7 @@ async function setupRemoteTemplate(options, controller) {
|
|
|
65
66
|
language,
|
|
66
67
|
packageManager,
|
|
67
68
|
depsInstalled: false,
|
|
68
|
-
|
|
69
|
+
cliCommand: await getCliCommand("", packageManager)
|
|
69
70
|
};
|
|
70
71
|
const tasks = [
|
|
71
72
|
{
|