Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt v2 route conventions in demo-store #747

Merged
merged 10 commits into from
Apr 12, 2023
118 changes: 118 additions & 0 deletions .changeset/early-jobs-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
'@shopify/hydrogen': patch
---

Adopt `v2_routeConvention` future flag

## `v2_routeConventions` migration steps

Remix v2 route conventions are just file renames. We just need to ensure when changing file name and file location, the import paths of other files are also updated.

Go to Remix docs for more details on the [V2 route convention](https://remix.run/docs/en/main/file-conventions/route-files-v2).

Rename and move the following files in the `routes` folder to adopt to V2 route convention.

<table>
<tr>
<th>Before</th>
<th>After (V2 route convention)</th>
</tr>
<tr>
<td>

```txt
app/routes/
├─ [sitemap.xml].tsx
├─ [robots.txt].tsx
└─ ($lang)/
├─ $shopid/orders/$token/
│ └─ authenticate.tsx
├─ account/
│ ├─ __private/
│ │ ├─ address/
│ │ │ └─ $id.tsx
│ │ ├─ orders.$id.tsx
│ │ ├─ edit.tsx
│ │ └─ logout.ts
│ └─ __public/
│ ├─ recover.tsx
│ ├─ login.tsx
│ ├─ register.tsx
│ ├─ activate.$id.$activationToken.tsx
│ └─ reset.$id.$resetToken.tsx
├─ api/
│ ├─ countries.tsx
│ └─ products.tsx
├─ collections/
│ ├─ index.tsx
│ ├─ $collectionHandle.tsx
│ └─ all.tsx
├─ journal/
│ ├─ index.tsx
│ └─ $journalHandle.tsx
├─ pages
│ └─ $pageHandle.tsx
├─ policies/
│ ├─ index.tsx
│ └─ $policyHandle.tsx
├─ products/
│ ├─ index.tsx
│ └─ $productHandle.tsx
├─ $.tsx
├─ account.tsx
├─ cart.tsx
├─ cart.$lines.tsx
├─ discount.$code.tsx
├─ featured-products.tsx
├─ index.tsx
└─ search.tsx
```

</td>
<td valign="top">

```txt
app/routes/
├─ [sitemap.xml].tsx
├─ [robots.txt].tsx
├─ ($lang).$shopid.orders.$token.authenticate.tsx
├─ ($lang).account.address.$id.tsx
├─ ($lang).account.orders.$id.tsx
├─ ($lang).account.edit.tsx
├─ ($lang).account.logout.ts
├─ ($lang).account.recover.tsx
├─ ($lang).account.login.tsx
├─ ($lang).account.register.tsx
├─ ($lang).account.activate.$id.$activationToken.tsx
├─ ($lang).account.reset.$id.$resetToken.tsx
├─ ($lang).api.countries.tsx
├─ ($lang).api.products.tsx
├─ ($lang).collections._index.tsx
├─ ($lang).collections.$collectionHandle.tsx
├─ ($lang).collections.all.tsx
├─ ($lang).journal._index.tsx
├─ ($lang).journal.$journalHandle.tsx
├─ ($lang).pages.$pageHandle.tsx
├─ ($lang).policies._index.tsx
├─ ($lang).policies.$policyHandle.tsx
├─ ($lang).products._index.tsx
├─ ($lang).products.$productHandle.tsx
├─ $.tsx
├─ ($lang)._index.tsx
├─ ($lang).account.tsx
├─ ($lang).cart.tsx
├─ ($lang).cart.$lines.tsx
├─ ($lang).discount.$code.tsx
├─ ($lang).featured-products.tsx
└─ ($lang).search.tsx
```

</td>
</tr>
</table>

### Optional

If you want to continue using nested folder routes but have the `v2_routeConvention` flag turned on, you may consider using the npm package [`@remix-run/v1-route-convention`](https://www.npmjs.com/package/@remix-run/v1-route-convention).

If you like the flat route convention but still wants a hybrid style of nested route folder, you may consider using the npm package [`remix-flat-routes`](https://www.npmjs.com/package/remix-flat-routes)
8 changes: 6 additions & 2 deletions templates/demo-store/app/components/FeaturedProducts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
Product,
ProductSortKeys,
} from '@shopify/hydrogen/storefront-api-types';
import {usePrefixPathWithLocale} from '~/lib/utils';

interface FeaturedProductsProps {
count: number;
Expand Down Expand Up @@ -45,10 +46,13 @@ export function FeaturedProducts({
.join('&'),
[count, sortKey, query, reverse],
);
const productsApiPath = usePrefixPathWithLocale(
`/api/products?${queryString}`,
);

useEffect(() => {
load(`/api/products?${queryString}`);
}, [load, queryString]);
load(productsApiPath);
}, [load, productsApiPath]);

return (
<>
Expand Down
14 changes: 13 additions & 1 deletion templates/demo-store/app/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@ import {MediaFile} from '@shopify/hydrogen';
import type {
MediaImage,
Media,
Metafield,
Video as MediaVideo,
} from '@shopify/hydrogen/storefront-api-types';
import {Heading, Text, Link} from '~/components';
import type {CollectionHero} from '~/routes/($lang)/index';

export interface CollectionHero {
byline: Metafield;
cta: Metafield;
handle: string;
heading: Metafield;
height?: 'full';
loading?: 'eager' | 'lazy';
spread: Metafield;
spreadSecondary: Metafield;
top?: boolean;
}

/**
* Hero component that renders metafields attached to collection resources
Expand Down
19 changes: 15 additions & 4 deletions templates/demo-store/app/components/SortFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@ import type {
Filter,
Collection,
} from '@shopify/hydrogen/storefront-api-types';
import {
AppliedFilter,
SortParam,
} from '~/routes/($lang)/collections/$collectionHandle';

export type AppliedFilter = {
label: string;
urlParam: {
key: string;
value: string;
};
};

export type SortParam =
| 'price-low-high'
| 'price-high-low'
| 'best-selling'
| 'newest'
| 'featured';

type Props = {
filters: Filter[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {getHeroPlaceholder} from '~/lib/placeholders';
import {seoPayload} from '~/lib/seo.server';
import type {
CollectionConnection,
Metafield,
ProductConnection,
} from '@shopify/hydrogen/storefront-api-types';
import {AnalyticsPageType} from '@shopify/hydrogen';
import {routeHeaders, CACHE_SHORT} from '~/data/cache';
import {type CollectionHero} from '~/components/Hero';

interface HomeSeoData {
shop: {
Expand All @@ -20,18 +20,6 @@ interface HomeSeoData {
};
}

export interface CollectionHero {
byline: Metafield;
cta: Metafield;
handle: string;
heading: Metafield;
height?: 'full';
loading?: 'eager' | 'lazy';
spread: Metafield;
spreadSecondary: Metafield;
top?: boolean;
}

export const headers = routeHeaders;

export async function loader({params, context}: LoaderArgs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
import invariant from 'tiny-invariant';
import {Button, Text} from '~/components';
import {assertApiErrors, getInputStyleClasses} from '~/lib/utils';
import type {AccountOutletContext} from '../edit';
import type {AccountOutletContext} from './($lang).account.edit';

interface ActionData {
formError?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import clsx from 'clsx';
import invariant from 'tiny-invariant';
import {Button, Text} from '~/components';
import {getInputStyleClasses, assertApiErrors} from '~/lib/utils';
import {getCustomer} from '../../account';
import {getCustomer} from './($lang).account';

export interface AccountOutletContext {
customer: Customer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import {Form, useActionData, type V2_MetaFunction} from '@remix-run/react';
import {useState} from 'react';
import {getInputStyleClasses} from '~/lib/utils';
import {doLogin} from './login';
import {doLogin} from './($lang).account.login';
import type {CustomerCreatePayload} from '@shopify/hydrogen/storefront-api-types';
import {Link} from '~/components';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import {
type AppLoadContext,
} from '@shopify/remix-oxygen';
import {flattenConnection} from '@shopify/hydrogen';
import {getFeaturedData} from './featured-products';
import {doLogout} from './account/__private/logout';
import {getFeaturedData} from './($lang).featured-products';
import {doLogout} from './($lang).account.logout';
import {usePrefixPathWithLocale} from '~/lib/utils';
import {CACHE_NONE, routeHeaders} from '~/data/cache';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen';
import {cartCreate} from './cart';
import {cartCreate} from './($lang).cart';

/**
* Automatically creates a new cart based on the URL and redirects straight to checkout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {ProductGrid} from '~/components/ProductGrid';
import {PRODUCT_CARD_FRAGMENT} from '~/data/fragments';
import {CACHE_SHORT, routeHeaders} from '~/data/cache';
import {seoPayload} from '~/lib/seo.server';
import type {AppliedFilter, SortParam} from '~/components/SortFilter';

export const headers = routeHeaders;

Expand All @@ -23,26 +24,10 @@ type VariantOptionFiltersQueryParam = Record<
'variantOption',
{name: string; value: string}
>;

export type AppliedFilter = {
label: string;
urlParam: {
key: string;
value: string;
};
};

type FiltersQueryParams = Array<
VariantFilterParam | PriceFiltersQueryParam | VariantOptionFiltersQueryParam
>;

export type SortParam =
| 'price-low-high'
| 'price-high-low'
| 'best-selling'
| 'newest'
| 'featured';

export async function loader({params, request, context}: LoaderArgs) {
const {collectionHandle} = params;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen';
import {getCartId} from '~/lib/utils';
import {cartCreate, cartDiscountCodesUpdate} from './cart';
import {cartCreate, cartDiscountCodesUpdate} from './($lang).cart';

/**
* Automatically applies a discount found on the url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import invariant from 'tiny-invariant';
import {PageHeader, Section} from '~/components';
import {ATTR_LOADING_EAGER} from '~/lib/const';
import {seoPayload} from '~/lib/seo.server';
import styles from '../../../styles/custom-font.css';
import styles from '../styles/custom-font.css';
import {routeHeaders, CACHE_LONG} from '~/data/cache';

const BLOG_HANDLE = 'journal';
Expand Down
1 change: 1 addition & 0 deletions templates/demo-store/remix.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
unstable_postcss: true,
unstable_tailwind: true,
v2_meta: true,
v2_routeConvention: true,
v2_errorBoundary: true,
v2_normalizeFormMethod: true,
},
Expand Down