Skip to content
This repository was archived by the owner on Jan 26, 2026. It is now read-only.

Commit 4a1a939

Browse files
authored
Merge branch 'Weaverse:main' into main
2 parents 569cb04 + cb8d552 commit 4a1a939

22 files changed

+3805
-2420
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Hydrogen upgrade guide: 2025.1.2 to 2025.1.3
2+
3+
----
4+
5+
## Features
6+
7+
### Add support for `v3_routeConfig` future flag. [#2722](https://github.com/Shopify/hydrogen/pull/2722)
8+
9+
#### Step: 1. Update your `vite.config.ts`. [#2722](https://github.com/Shopify/hydrogen/pull/2722)
10+
11+
[docs](https://remix.run/docs/en/main/start/future-flags#v3_routeconfig)
12+
[#2722](https://github.com/Shopify/hydrogen/pull/2722)
13+
export default defineConfig({
14+
plugins: [
15+
hydrogen(),
16+
oxygen(),
17+
remix({
18+
presets: [hydrogen.v3preset()], // Update this to hydrogen.v3preset()
19+
future: {
20+
v3_fetcherPersist: true,
21+
v3_relativeSplatPath: true,
22+
v3_throwAbortReason: true,
23+
v3_lazyRouteDiscovery: true,
24+
v3_singleFetch: true,
25+
v3_routeConfig: true, // add this flag
26+
},
27+
}),
28+
tsconfigPaths(),
29+
],
30+
31+
#### Step: 2. Update your `package.json` and install the new packages. Make sure to match the Remix version along with other Remix npm packages and ensure the versions are 2.16.1 or above. [#2722](https://github.com/Shopify/hydrogen/pull/2722)
32+
33+
[docs](https://remix.run/docs/en/main/start/future-flags#v3_routeconfig)
34+
[#2722](https://github.com/Shopify/hydrogen/pull/2722)
35+
"devDependencies": {
36+
...
37+
"@remix-run/fs-routes": "^2.16.1",
38+
"@remix-run/route-config": "^2.16.1",
39+
40+
#### Step: 3. Move the `Layout` component export from `root.tsx` into its own file. Make sure to supply an `<Outlet>` so Remix knows where to inject your route content. [#2722](https://github.com/Shopify/hydrogen/pull/2722)
41+
42+
[docs](https://remix.run/docs/en/main/start/future-flags#v3_routeconfig)
43+
[#2722](https://github.com/Shopify/hydrogen/pull/2722)
44+
// /app/layout.tsx
45+
import {Outlet} from '@remix-run/react';
46+
47+
export default function Layout() {
48+
const nonce = useNonce();
49+
const data = useRouteLoaderData<RootLoader>('root');
50+
51+
return (
52+
<html lang="en">
53+
...
54+
<Outlet />
55+
...
56+
</html>
57+
);
58+
}
59+
60+
// Remember to remove the Layout export from your root.tsx
61+
62+
63+
#### Step: 4. Add a `routes.ts` file. This is your new Remix route configuration file. [#2722](https://github.com/Shopify/hydrogen/pull/2722)
64+
65+
[docs](https://remix.run/docs/en/main/start/future-flags#v3_routeconfig)
66+
[#2722](https://github.com/Shopify/hydrogen/pull/2722)
67+
import {flatRoutes} from '@remix-run/fs-routes';
68+
import {layout, type RouteConfig} from '@remix-run/route-config';
69+
import {hydrogenRoutes} from '@shopify/hydrogen';
70+
71+
export default hydrogenRoutes([
72+
// Your entire app reading from routes folder using Layout from layout.tsx
73+
layout('./layout.tsx', (await flatRoutes())),
74+
]) satisfies RouteConfig;
75+
76+
----

app/routes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { flatRoutes } from "@remix-run/fs-routes";
2+
3+
export default flatRoutes();

app/routes/($locale).account._index.tsx

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type { CustomerAddressInput } from "@shopify/hydrogen/customer-account-ap
1717
import {
1818
type ActionFunctionArgs,
1919
type LoaderFunctionArgs,
20-
json,
20+
data,
2121
} from "@shopify/remix-oxygen";
2222
import type {
2323
CustomerFragment,
@@ -56,7 +56,7 @@ export async function loader({ request, context }: LoaderFunctionArgs) {
5656
throw Error("Customer orders not found");
5757
}
5858

59-
return json({ customer: data.customer });
59+
return data({ customer: data.customer });
6060
}
6161

6262
export async function action({ request, context, params }: ActionFunctionArgs) {
@@ -75,11 +75,9 @@ export async function action({ request, context, params }: ActionFunctionArgs) {
7575
// this will ensure redirecting to login never happen for mutatation
7676
const isLoggedIn = await customerAccount.isLoggedIn();
7777
if (!isLoggedIn) {
78-
return json(
78+
return data(
7979
{ error: { [addressId]: "Unauthorized" } },
80-
{
81-
status: 401,
82-
},
80+
{ status: 401 }
8381
);
8482
}
8583

@@ -130,25 +128,21 @@ export async function action({ request, context, params }: ActionFunctionArgs) {
130128
throw new Error("Customer address create failed.");
131129
}
132130

133-
return json({
131+
return data({
134132
error: null,
135133
createdAddress: data?.customerAddressCreate?.customerAddress,
136134
defaultAddress,
137135
});
138136
} catch (error: unknown) {
139137
if (error instanceof Error) {
140-
return json(
138+
return data(
141139
{ error: { [addressId]: error.message } },
142-
{
143-
status: 400,
144-
},
140+
{ status: 400 }
145141
);
146142
}
147-
return json(
143+
return data(
148144
{ error: { [addressId]: error } },
149-
{
150-
status: 400,
151-
},
145+
{ status: 400 }
152146
);
153147
}
154148
}
@@ -182,25 +176,21 @@ export async function action({ request, context, params }: ActionFunctionArgs) {
182176

183177
// });
184178

185-
return json({
179+
return data({
186180
error: null,
187181
updatedAddress: address,
188182
defaultAddress,
189183
});
190184
} catch (error: unknown) {
191185
if (error instanceof Error) {
192-
return json(
186+
return data(
193187
{ error: { [addressId]: error.message } },
194-
{
195-
status: 400,
196-
},
188+
{ status: 400 }
197189
);
198190
}
199-
return json(
191+
return data(
200192
{ error: { [addressId]: error } },
201-
{
202-
status: 400,
203-
},
193+
{ status: 400 }
204194
);
205195
}
206196
}
@@ -227,48 +217,38 @@ export async function action({ request, context, params }: ActionFunctionArgs) {
227217
throw new Error("Customer address delete failed.");
228218
}
229219

230-
return json({ error: null, deletedAddress: addressId });
220+
return data({ error: null, deletedAddress: addressId });
231221
} catch (error: unknown) {
232222
if (error instanceof Error) {
233-
return json(
223+
return data(
234224
{ error: { [addressId]: error.message } },
235-
{
236-
status: 400,
237-
},
225+
{ status: 400 }
238226
);
239227
}
240-
return json(
228+
return data(
241229
{ error: { [addressId]: error } },
242-
{
243-
status: 400,
244-
},
230+
{ status: 400 }
245231
);
246232
}
247233
}
248234

249235
default: {
250-
return json(
236+
return data(
251237
{ error: { [addressId]: "Method not allowed" } },
252-
{
253-
status: 405,
254-
},
238+
{ status: 405 }
255239
);
256240
}
257241
}
258242
} catch (error: unknown) {
259243
if (error instanceof Error) {
260-
return json(
244+
return data(
261245
{ error: error.message },
262-
{
263-
status: 400,
264-
},
246+
{ status: 400 }
265247
);
266248
}
267-
return json(
249+
return data(
268250
{ error },
269-
{
270-
status: 400,
271-
},
251+
{ status: 400 }
272252
);
273253
}
274254
}

app/routes/($locale).account.orders._index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
flattenConnection,
66
getPaginationVariables,
77
} from "@shopify/hydrogen";
8-
import { type LoaderFunctionArgs, json } from "@shopify/remix-oxygen";
8+
import { type LoaderFunctionArgs, data } from "@shopify/remix-oxygen";
99
import type {
1010
CustomerOrdersFragment,
1111
OrderItemFragment,
@@ -36,7 +36,7 @@ export async function loader({ request, context }: LoaderFunctionArgs) {
3636
throw Error("Customer orders not found");
3737
}
3838

39-
return json({ customer: data.customer });
39+
return data({ customer: data.customer });
4040
}
4141

4242
export default function Orders() {

app/routes/($locale).account.profile.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {CustomerFragment} from 'customer-accountapi.generated';
22
import type {CustomerUpdateInput} from '@shopify/hydrogen/customer-account-api-types';
33
import {CUSTOMER_UPDATE_MUTATION} from '~/graphql/customer-account/CustomerUpdateMutation';
44
import {
5-
json,
5+
data,
66
redirect,
77
type ActionFunctionArgs,
88
type LoaderFunctionArgs,
@@ -27,16 +27,14 @@ export const meta: MetaFunction = () => {
2727
export async function loader({context}: LoaderFunctionArgs) {
2828
await context.customerAccount.handleAuthStatus();
2929

30-
return json(
31-
{}
32-
);
30+
return data({});
3331
}
3432

3533
export async function action({request, context}: ActionFunctionArgs) {
3634
const {customerAccount} = context;
3735

3836
if (request.method !== 'PUT') {
39-
return json({error: 'Method not allowed'}, {status: 405});
37+
return data({ error: 'Method not allowed' }, { status: 405 });
4038
}
4139

4240
const form = await request.formData();
@@ -71,19 +69,18 @@ export async function action({request, context}: ActionFunctionArgs) {
7169
throw new Error('Customer profile update failed.');
7270
}
7371

74-
return json(
72+
return data(
7573
{
7674
error: null,
7775
customer: data?.customerUpdate?.customer,
78-
},
79-
76+
}
8077
);
8178
} catch (error: any) {
82-
return json(
79+
return data(
8380
{error: error.message, customer: null},
8481
{
8582
status: 400,
86-
},
83+
}
8784
);
8885
}
8986
}

app/routes/($locale).account.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {json, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
1+
import { data, redirect, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
22
import {Form, NavLink, Outlet, useLoaderData} from '@remix-run/react';
33
import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
44

@@ -15,7 +15,7 @@ export async function loader({context}: LoaderFunctionArgs) {
1515
throw new Error('Customer not found');
1616
}
1717

18-
return json(
18+
return data(
1919
{customer: data.customer},
2020
{
2121
headers: {

app/routes/($locale).api.customer.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ActionFunction, ActionFunctionArgs, json } from "@remix-run/server-runtime"
1+
import { ActionFunction, ActionFunctionArgs } from "@remix-run/server-runtime"
2+
import { data } from "@shopify/remix-oxygen"
23
import { CustomerCreateMutation } from "storefrontapi.generated"
34
import { CUSTOMER_CREATE_MUTATION } from "~/data/mutations"
45

@@ -22,11 +23,11 @@ export let action: ActionFunction = async ({request, context}: ActionFunctionArg
2223
let customer = customerCreate?.customer
2324
let errors = customerCreate?.customerUserErrors || queryError
2425
if (errors && errors.length) {
25-
return json({errors}, {
26+
return data({ errors }, {
2627
status: 200
2728
})
2829
}
29-
return json({customer}, {
30+
return data({ customer }, {
3031
status: 201
3132
})
3233
}

app/routes/($locale).blogs.$blogHandle.$articleHandle.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {MetaFunction} from '@remix-run/react';
22
import {getSeoMeta, type SeoConfig} from '@shopify/hydrogen';
3-
import {json} from '@shopify/remix-oxygen';
3+
import { data } from '@shopify/remix-oxygen';
44
import {type RouteLoaderArgs} from '@weaverse/hydrogen';
55
import {routeHeaders} from '~/data/cache';
66
import {ARTICLE_QUERY} from '~/graphql/data/queries';
@@ -46,7 +46,7 @@ export async function loader(args: RouteLoaderArgs) {
4646

4747
const seo = seoPayload.article({article, url: request.url});
4848

49-
return json({
49+
return data({
5050
article,
5151
blog: {
5252
handle: params.blogHandle,

app/routes/($locale).blogs.$blogHandle._index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {MetaFunction} from '@remix-run/react';
22
import {flattenConnection, getSeoMeta, type SeoConfig} from '@shopify/hydrogen';
3-
import {json} from '@shopify/remix-oxygen';
3+
import { data } from '@shopify/remix-oxygen';
44
import {type RouteLoaderArgs} from '@weaverse/hydrogen';
55
import {routeHeaders} from '~/data/cache';
66
import {BLOGS_PAGE_QUERY} from '~/graphql/data/queries';
@@ -44,7 +44,7 @@ export const loader = async (args: RouteLoaderArgs) => {
4444

4545
const seo = seoPayload.blog({blog, url: request.url});
4646

47-
return json({
47+
return data({
4848
blog,
4949
articles,
5050
seo,

app/routes/($locale).blogs._index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { json, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
1+
import { data, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
22
import { Link, useLoaderData, type MetaFunction } from '@remix-run/react';
33
import { Pagination, getPaginationVariables } from '@shopify/hydrogen';
44
import { WeaverseContent } from '~/weaverse';
@@ -21,7 +21,7 @@ export const loader = async ({
2121
},
2222
});
2323

24-
return json({ blogs, weaverseData: await context.weaverse.loadPage({ type: 'BLOG' }), });
24+
return data({ blogs, weaverseData: await context.weaverse.loadPage({ type: 'BLOG' }), });
2525
};
2626

2727
export default function Blogs() {

0 commit comments

Comments
 (0)