I've built a Shopify storefront with Next.js.
I've been using Shopify for work for a while now, and I was interested in Next.js because it supports various rendering methods such as SSR, SSG and ISR, so I decided to combine the two and build a store.
The design is based on Shopify's default Debut theme (which is now Dawn).
Technology used, etc.
Store: https://nextjs-shopify-store.vercel.app
Repository: https://github.com/naoya-kuma1990/nextjs-shopify-store
Technologies used: React, Next.js, TypeScript, Tailwind CSS, Material UI, Shopify JavaScript Buy SDK, Store Front API (Graph QL)
Implemented pages: Collection (product list), product details, cart, search results
Rate Limit for Next.js and Store Front API
As I mentioned at the beginning of this article, Next.js is a React framework that supports SSR and ISR. I used it this time because I thought that "when it comes to e-commerce sites, it's natural to support SEO, and if you want to achieve that with React, Next.js is the way to go". However, as it turns out, the site I made this time fails SEO because all the major information fetching, such as product information fetching, are performed on the client side lol.
This is because there is a cost limit called "API Rate Limits" on access to Shopify's API, and access is restricted depending on the type of API. You can read more about it in the official website, but basically, each store (strictly speaking, the private app that is the access point) has a set number of points, and if the points are consumed, the request will become an error until the points are recovered.
Therefore, the two Admin APIs (REST and GraphQL) can quickly become too costly to run every time a large number of users access the site, so there is Store Front API . Unlike the Admin API, this one is limited by IP. As a result, the Store Front API does not incur any cost overruns, as long as a certain amount of information is hit from the client side.
For these reasons, SSR is not the first choice for building a store front using Shopify's API, as SSR would mean hitting the API for every user access, which would quickly lead to cost overruns no matter which API you use.
The options are to use an ISR to hit the API at regular intervals and render it as a static page, or to use a CSR to hit the Store Front API each time. This time I chose CSR.
Get information in useEffect in page component
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/pages/collections/%5Bhandle%5D.tsx#L30-L60
Query the Store Front API using a custom client
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/lib/graphql/collection/getCollectionWithProducts.ts#L69-L136
JavaScript SDK and custom clients
The JavaScript Buy SDK is an SDK for hitting the Store Front API. Basically, you can use this SDK for product information and cart operations, so I thought I'd use it entirely, but there were some problems. The SDK is only used for cart operations such as adding and deleting products, while the GraphQL client library (graphql-request
) is used for retrieving product information and search functions on the product page, directly hitting the Store Front API. This is because, first of all, JS Buy SDK seems to have an old type definition of TypeScript, and the type information does not match the property that can actually be retrieved, and it is necessary to extend the type definition partially by oneself. This was the first time for me to extend the type definitions, so I learned a lot, but it was troublesome to determine which properties were typed and which were not. Also, the basic properties supported by the SDK are only a part of the information that can be retrieved by the Store Front API as described in the official documentation, and when I tried to extend the SDK, it seemed to be so cumbersome (for example, the collection page does not support sorting of products). (Sorting is achieved with the SDK like this)
Therefore, I decided to use the SDK only for cart operations where the SDK is sufficient, extending the library's typedefs, and to define a custom client to directly access to the Store Front API for the rest.
JS Buy SDK
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/lib/client.ts
Custom Client
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/lib/graphql/customClient.ts
Extending the SDK type definitions
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/types/shopify-buy.d.ts
Custom hooks
I made a custom hook for a operation of a cart.
Custom hooks (useCart)
https://github.com/momonoki1990/nextjs-shopify-store/blob/a91df30dd6fe4f6e6f057294dbbbb71876602ec9/lib/useCart.ts#L17-L130
Tailwind CSS and Material UI
To recreate Shopify's default theme Debut (Dawn is the default theme now), I used Tailwind CSS and Material UI components for animations like drawers and skeletons (dummies displayed during the initial drawing). I personally used Tailwind CSS when I wrote my theme in Liquid and was very impressed with how it solved the problem of CSS being global. However, I still found it very useful to use Tailwind to integrate styling with HTML and reduce the amount of writing.
We also used Tailwind in conjunction with Material UI, but as Tailwind is using class name and Material UI is a component, there were no conflicts. I don't think it's recommended to use different CSS frameworks together, so I don't think I'd personally recommend it for a real project.
Hydrogen and Oxygen.
Hydrogen includes commerce-specific components such as a cart, variant picker and media gallery to take the complexity out of building a custom storefront.
At the same time, "Oxygen" was announced. This is a fast and global way to host Hydrogen directly on Shopify, optimised for eCommerce.
Hydrogen and Oxygen are now available
See also: Hydrogen
A React framework called Hydrogen, which provides components and Hooks that look like I wrote by myself, and a server called Oxygen, which hosts Hydrogen, are being released.
With the tide of front-end development completely shifting to SPA frameworks, developing themes with Liquid has been a challenge in its own right, but Shopify is going to join the bandwagon, which will improve the UX, development speed, and development experience.
Others
Can't show the total number of pages in the collection page.
It would be nice if there was a property for the total number of pages, but the Store Front API doesn't allow us to get the total number of products in a collection. So, after retrieving a certain number of products in a collection (up to 250), we can determine if there is a next page frompageInfo.haxNextPage
, but can't display the total number of pages, like "1 / 12". The solution I can think of is to use ISR to get information about the collection at regular intervals on the collection page, get the collection information from the Store Front API or GraphQL Admin API, and then get the total number of products.Products displayed in the store
I'm using an app called Oberlo.The checkout (after "proceed to checkout") is the same as the theme, which takes you to the payment page provided by Shopify
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/lib/useCart.ts#L110Sorting products in a collection
https://github.com/momonoki1990/nextjs-shopify-store/blob/main/lib/graphql/collection/getCollectionWithProducts.ts#L87
The arguments of the query are listed in "arguments" of "products" in QueryRoot.Keyword search for product titles
https://github.com/momonoki1990/nextjs-shopify-store/blob/a91df30dd6fe4f6e6f057294dbbbb71876602ec9/lib/graphql/product/ getProductsByTitle.ts#L52-L90
Partial matching on query
Shopify GraphQL partial matching on query filter
https://stackoverflow.com/questions/51742384/shopify-graphql-partial-matching-on-query-filter
Thank you for reading !
Top comments (6)
Great project I just started learining shopify and this will inspire me to go forward without hesitating and also Next Js is my favourite framework till now so it is great to see such a project with Next Js. Thank you and carry on.
@momonoki1990 As you mentioned in the first point of "Others" section.
I'm not sure if I fully understand the challenge you are facing but getting the product count of a created collection is accessible through storefront api.
https://.com/collections/all.json look for the products_count key
@ahmadint
Thank you for your advise !
Maybe this is Rest Admin API endpoint of shopify, not GraphQL Storefrot API.
And, count rate limit way is different between Rest Admin and GraphQL StoreFront, so Rest Admin API would not withstand a large number of requests made each time the page is accessed.
Hi @momonoki1990 ,
I love the design!
Could I ask what license this is under? I'd like to use it for some of my own projects but they might end up being used commercially. I noticed you didn't have a license on your github repo. Thanks!
@ilyas
Thank you for your comment.
And sorry for the very late reply ... 🙏!!!
I added MIT License to this repository !
Thank you.
This is wonderful 🔥🔥