Skip to content

Commit

Permalink
Add codegen to demo-store (#937)
Browse files Browse the repository at this point in the history
* Add codegen to demo-store

* Remove hardcoded types for mutations

* Use codegen in sitemap route

* Use codegen in journal-handle route

* Use codegen in policies routes

* Use codegen in page route

* Use codegen in product routes

* Use codegen in order routes

* Use codegen in product and account routes

* Use codegen in journal

* Use codegen in product-handle

* Use codegen in search and featured-products. Reuse fragment

* Use codegen in collections route

* Fix query

* Remove codegen flag when transpiling project

* Implement generated root types in demo-store

* Implement generated homepage types in demo-store

* track generated demo-store types

* Fix featured products result types

* ESLint auto fix import order

* Fix article type from flattenConnection

* Fix orders type from flattenConnection

* Fix possible undefined

* Changesets

* Changesets -- add link to PR

---------

Co-authored-by: Juan P. Prieto <juanpablo.prieto@shopify.com>
  • Loading branch information
frandiox and juanpprieto authored May 26, 2023
1 parent 4c5cdfd commit b219552
Show file tree
Hide file tree
Showing 46 changed files with 2,714 additions and 700 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-dolphins-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/cli-hydrogen': patch
---

Remove `--codegen-unstable` flag from scripts when transpiling projects from TypeScript to JavaScript.
9 changes: 9 additions & 0 deletions .changeset/dull-stingrays-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'demo-store': patch
---

Start using GraphQL code generation. This allows us to have full-stack type-safety and better developer experience.

As a result of the above, we've fixed issues where the frontend was accessing data that was not correctly fetched from the Storefront API. For example, missing `product.vendor` or accessing `totalPrice` instead of `totalPriceV2`.

To enable the unstable codegen feature in your project, run your dev command as `shopify hydrogen dev --codegen-unstable`. See the [changes associated here](https://github.com/Shopify/hydrogen/pull/937/files) for examples.
7 changes: 7 additions & 0 deletions packages/cli/src/lib/transpile-ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ export async function transpileProject(projectDir: string) {
}
}

if (pkgJson.scripts?.dev) {
pkgJson.scripts.dev = pkgJson.scripts.dev.replace(
/\s*--codegen(-unstable)?/,
'',
);
}

await fs.writeFile(
path.join(projectDir, 'package.json'),
JSON.stringify(pkgJson, null, 2),
Expand Down
8 changes: 3 additions & 5 deletions templates/demo-store/app/components/AccountAddressBook.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import {Form} from '@remix-run/react';
import type {
Customer,
MailingAddress,
} from '@shopify/hydrogen/storefront-api-types';
import type {MailingAddress} from '@shopify/hydrogen/storefront-api-types';

import type {CustomerDetailsFragment} from 'storefrontapi.generated';
import {Button, Link, Text} from '~/components';

export function AccountAddressBook({
customer,
addresses,
}: {
customer: Customer;
customer: CustomerDetailsFragment;
addresses: MailingAddress[];
}) {
return (
Expand Down
9 changes: 6 additions & 3 deletions templates/demo-store/app/components/AccountDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type {Customer} from '@shopify/hydrogen/storefront-api-types';

import type {CustomerDetailsFragment} from 'storefrontapi.generated';
import {Link} from '~/components';

export function AccountDetails({customer}: {customer: Customer}) {
export function AccountDetails({
customer,
}: {
customer: CustomerDetailsFragment;
}) {
const {firstName, lastName, email, phone} = customer;

return (
Expand Down
24 changes: 11 additions & 13 deletions templates/demo-store/app/components/FeaturedCollections.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import {Image} from '@shopify/hydrogen';
import type {Collection} from '@shopify/hydrogen/storefront-api-types';

import type {HomepageFeaturedCollectionsQuery} from 'storefrontapi.generated';
import {Heading, Section, Grid, Link} from '~/components';

type FeaturedCollectionsProps = HomepageFeaturedCollectionsQuery & {
title?: string;
[key: string]: any;
};

export function FeaturedCollections({
collections,
title = 'Collections',
...props
}: {
collections: Collection[];
title?: string;
[key: string]: any;
}) {
const haveCollections = collections && collections.length > 0;
}: FeaturedCollectionsProps) {
const haveCollections = collections?.nodes?.length > 0;
if (!haveCollections) return null;

const items = collections.filter((item) => item.image).length;
const collectionsWithImage = collections.nodes.filter((item) => item.image);

return (
<Section {...props} heading={title}>
<Grid items={items}>
{collections.map((collection) => {
if (!collection?.image) {
return null;
}
<Grid items={collectionsWithImage.length}>
{collectionsWithImage.map((collection) => {
return (
<Link key={collection.id} to={`/collections/${collection.handle}`}>
<div className="grid gap-4">
Expand Down
13 changes: 4 additions & 9 deletions templates/demo-store/app/components/FeaturedSection.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import {useEffect} from 'react';
import {useFetcher} from '@remix-run/react';
import type {Collection, Product} from '@shopify/hydrogen/storefront-api-types';

import {usePrefixPathWithLocale} from '~/lib/utils';
import type {FeaturedData} from '~/routes/($locale).featured-products';

import {FeaturedCollections} from './FeaturedCollections';
import {ProductSwimlane} from './ProductSwimlane';

export interface FeaturedData {
featuredCollections: Collection[];
featuredProducts: Product[];
}

export function FeaturedSection() {
const {load, data} = useFetcher();
const {load, data} = useFetcher<FeaturedData>();
const path = usePrefixPathWithLocale('/featured-products');

useEffect(() => {
Expand All @@ -22,11 +17,11 @@ export function FeaturedSection() {

if (!data) return null;

const {featuredCollections, featuredProducts} = data as FeaturedData;
const {featuredCollections, featuredProducts} = data;

return (
<>
{featuredCollections.length < 2 && (
{featuredCollections.nodes.length < 2 && (
<FeaturedCollections
title="Popular Collections"
collections={featuredCollections}
Expand Down
21 changes: 7 additions & 14 deletions templates/demo-store/app/components/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import clsx from 'clsx';
import type {SerializeFrom} from '@shopify/remix-oxygen';
import {MediaFile} from '@shopify/hydrogen';
import type {
MediaImage,
Media,
Metafield,
Video as MediaVideo,
} from '@shopify/hydrogen/storefront-api-types';

import type {CollectionContentFragment} from 'storefrontapi.generated';
import {Heading, Text, Link} from '~/components';

export interface CollectionHero {
byline: Metafield;
cta: Metafield;
handle: string;
heading: Metafield;
type HeroProps = CollectionContentFragment & {
height?: 'full';
loading?: 'eager' | 'lazy';
spread: Metafield;
spreadSecondary: Metafield;
top?: boolean;
}
loading?: HTMLImageElement['loading'];
};

/**
* Hero component that renders metafields attached to collection resources
Expand All @@ -35,7 +28,7 @@ export function Hero({
spread,
spreadSecondary,
top,
}: SerializeFrom<CollectionHero>) {
}: HeroProps) {
return (
<Link to={`/collections/${handle}`}>
<section
Expand Down Expand Up @@ -89,11 +82,11 @@ export function Hero({
);
}

interface SpreadMediaProps {
type SpreadMediaProps = {
data: Media | MediaImage | MediaVideo;
loading?: HTMLImageElement['loading'];
sizes: string;
}
};

function SpreadMedia({data, loading, sizes}: SpreadMediaProps) {
return (
Expand Down
40 changes: 18 additions & 22 deletions templates/demo-store/app/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {useWindowScroll} from 'react-use';
import {Disclosure} from '@headlessui/react';
import {Suspense, useEffect, useMemo} from 'react';

import type {LayoutQuery} from 'storefrontapi.generated';
import {
Drawer,
useDrawer,
Expand All @@ -21,23 +22,21 @@ import {
CartLoading,
Link,
} from '~/components';
import {
type EnhancedMenu,
type EnhancedMenuItem,
useIsHomePath,
} from '~/lib/utils';
import type {ChildEnhancedMenuItem} from '~/lib/utils';
import {type EnhancedMenu, useIsHomePath} from '~/lib/utils';
import {useIsHydrated} from '~/hooks/useIsHydrated';
import {useCartFetchers} from '~/hooks/useCartFetchers';

import type {LayoutData} from '../root';

export function Layout({
children,
layout,
}: {
type LayoutProps = {
children: React.ReactNode;
layout: LayoutData;
}) {
layout: LayoutQuery & {
headerMenu?: EnhancedMenu | null;
footerMenu?: EnhancedMenu | null;
};
};

export function Layout({children, layout}: LayoutProps) {
const {headerMenu, footerMenu} = layout;
return (
<>
<div className="flex flex-col min-h-screen">
Expand All @@ -46,15 +45,12 @@ export function Layout({
Skip to content
</a>
</div>
<Header
title={layout?.shop.name ?? 'Hydrogen'}
menu={layout?.headerMenu}
/>
{headerMenu && <Header title={layout.shop.name} menu={headerMenu} />}
<main role="main" id="mainContent" className="flex-grow">
{children}
</main>
</div>
<Footer menu={layout?.footerMenu} />
{footerMenu && <Footer menu={footerMenu} />}
</>
);
}
Expand Down Expand Up @@ -432,7 +428,7 @@ function Footer({menu}: {menu?: EnhancedMenu}) {
);
}

const FooterLink = ({item}: {item: EnhancedMenuItem}) => {
function FooterLink({item}: {item: ChildEnhancedMenuItem}) {
if (item.to.startsWith('http')) {
return (
<a href={item.to} target={item.target} rel="noopener noreferrer">
Expand All @@ -446,7 +442,7 @@ const FooterLink = ({item}: {item: EnhancedMenuItem}) => {
{item.title}
</Link>
);
};
}

function FooterMenu({menu}: {menu?: EnhancedMenu}) {
const styles = {
Expand All @@ -456,7 +452,7 @@ function FooterMenu({menu}: {menu?: EnhancedMenu}) {

return (
<>
{(menu?.items || []).map((item: EnhancedMenuItem) => (
{(menu?.items || []).map((item) => (
<section key={item.id} className={styles.section}>
<Disclosure>
{({open}) => (
Expand All @@ -480,7 +476,7 @@ function FooterMenu({menu}: {menu?: EnhancedMenu}) {
<Suspense data-comment="This suspense fixes a hydration bug in Disclosure.Panel with static prop">
<Disclosure.Panel static>
<nav className={styles.nav}>
{item.items.map((subItem) => (
{item.items.map((subItem: ChildEnhancedMenuItem) => (
<FooterLink key={subItem.id} item={subItem} />
))}
</nav>
Expand Down
33 changes: 31 additions & 2 deletions templates/demo-store/app/components/OrderCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {flattenConnection, Image} from '@shopify/hydrogen';
import type {Order} from '@shopify/hydrogen/storefront-api-types';

import type {OrderCardFragment} from 'storefrontapi.generated';
import {Heading, Text, Link} from '~/components';
import {statusMessage} from '~/lib/utils';

export function OrderCard({order}: {order: Order}) {
export function OrderCard({order}: {order: OrderCardFragment}) {
if (!order?.id) return null;
const [legacyOrderId, key] = order!.id!.split('/').pop()!.split('?');
const lineItems = flattenConnection(order?.lineItems);
Expand Down Expand Up @@ -81,3 +81,32 @@ export function OrderCard({order}: {order: Order}) {
</li>
);
}

export const ORDER_CARD_FRAGMENT = `#graphql
fragment OrderCard on Order {
id
orderNumber
processedAt
financialStatus
fulfillmentStatus
currentTotalPrice {
amount
currencyCode
}
lineItems(first: 2) {
edges {
node {
variant {
image {
url
altText
height
width
}
}
title
}
}
}
}
`;
3 changes: 2 additions & 1 deletion templates/demo-store/app/components/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {ShopifyAnalyticsProduct} from '@shopify/hydrogen';
import {flattenConnection, Image, Money, useMoney} from '@shopify/hydrogen';
import type {MoneyV2, Product} from '@shopify/hydrogen/storefront-api-types';

import type {ProductCardFragment} from 'storefrontapi.generated';
import {Text, Link, AddToCartButton} from '~/components';
import {isDiscounted, isNewArrival} from '~/lib/utils';
import {getProductPlaceholder} from '~/lib/placeholders';
Expand All @@ -15,7 +16,7 @@ export function ProductCard({
onClick,
quickAdd,
}: {
product: Product;
product: ProductCardFragment;
label?: string;
className?: string;
loading?: HTMLImageElement['loading'];
Expand Down
Loading

0 comments on commit b219552

Please sign in to comment.