Giter Site home page Giter Site logo

maxvien / next-shopify-storefront Goto Github PK

View Code? Open in Web Editor NEW
694.0 21.0 120.0 1.8 MB

๐Ÿ› A Shopping Cart built with TypeScript, Tailwind CSS, Headless UI, Next.js, React.js, Shopify Hydrogen React,... and Shopify Storefront GraphQL API.

Home Page: https://next-shopify-storefront.vercel.app

License: MIT License

JavaScript 0.16% TypeScript 99.83% CSS 0.01%
graphql headlessui shopify-storefront-api shopify-storefronts tailwindcss graphql-zeus seo eslint incremental-static-regeneration nextjs

next-shopify-storefront's Introduction

๐Ÿ› Next Shopify Storefront

A Shopping Cart built with TypeScript, Tailwind CSS, Headless UI, Next.js, React.js, Shopify Hydrogen React,... and Shopify Storefront GraphQL API.

Next Shopify Storefront - GitHub Repo Stars Next Shopify Storefront - GitHub forks Next Shopify Storefront - Started Years

Tutorials

Experience

These are my experiences when I have been working on this project:

If you like this project, hit the STAR button to bookmark it โญ๏ธ

Demonstration

You can visit here to see the demo: https://next-shopify-storefront.vercel.app/

Installation

Clone the source code into your computer.

git clone https://github.com/maxvien/next-shopify-storefront.git

Install the project's dependencies.

npm install

Usage

First, you need to set the below environment variables in the .env file or your deployment platforms.

  • NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
  • NEXT_PUBLIC_SHOPIFY_STOREFRONT_API_TOKEN
  • NEXT_PUBLIC_SHOPIFY_STOREFRONT_API_VERSION

You can follow the Shopify Storefront GraphQL API documentation to get Storefront API information.

Develop

Develop the project in development mode.

npm run dev

Build

Build the project in production mode.

npm run build

Start

Start the project in production mode.

npm run start

Lint

Analyze the code to find problems with eslint and prettier.

npm run lint

Automatically fix problems.

npm run fix

Visual Studio Code Extensions

To speed up your productivity, you can install these extensions:

Related Projects

  • Shopify Data Faker โ€ข A Shopify development tool for generating dummy store data.
  • Bootstrap Shopify Theme โ€ข A free Shopify Theme built with Bootstrap, BEM, Liquid, Sass, ESNext, Theme Tools, ... and Webpack.
  • Next Shopify Storefront (v2) โ€ข A Shopping Cart built with TypeScript, Emotion, Next.js, React.js, React Query, Shopify Storefront GraphQL API, ... and Material UI.
  • Next Shopify Storefront (v1) โ€ข A Shopping Cart built with TypeScript, NextJS, React, Redux, Apollo Client, Shopify Storefront GraphQL API, ... and Material UI.

Star History

Star History Chart

next-shopify-storefront's People

Contributors

dependabot[bot] avatar iduuck avatar maxvien avatar mohamedbassem avatar zomars avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

next-shopify-storefront's Issues

Startup error reports conflicting versions of graphql

Hey, just getting started with this project and hitting an issue straight away:

$ npm run dev

> [email protected] dev
> nps -s dev

[next] nps is executing `next` : next dev
[graphql] nps is executing `graphql` : nps graphql.download && nps "graphql.codegen --watch"
[next] ready - started server on 0.0.0.0:3000, url: http://localhost:3000
[next] info  - Loaded env from C:\Users\rhysv\Projects\next-shopify-storefront\.env
[graphql] nps is executing `graphql.download` : apollo client:download-schema -c src/services/shopify/apollo.config.js src/services/shopify/schema.gql
[next] info  - Using webpack 4. Reason: webpack5 flag is set to false in next.config.js https://nextjs.org/docs/messages/webpack5
[graphql]  ยป   Warning: apollo update available from 2.33.6 to 2.33.7.
[graphql] Loading Apollo Project [started]
[next] info  - Using external babel configuration from C:\Users\rhysv\Projects\next-shopify-storefront\.babelrc
[graphql] Loading Apollo Project [completed]
[graphql] Saving schema to src/services/shopify/schema.gql [started]
[graphql] Saving schema to src/services/shopify/schema.gql [failed]
[graphql] โ†’ Cannot use GraphQLNonNull "String!" from another module or realm.
[graphql]
[graphql] Ensure that there is only one instance of "graphql" in the node_modules
[graphql] directory. If different versions of "graphql" are the dependencies of other
[graphql] relied on modules, use "resolutions" to ensure only one version is installed.
[graphql]
[graphql] https://yarnpkg.com/en/docs/selective-version-resolutions
[graphql]
[graphql] Duplicate "graphql" modules cannot be used at the same time since different
[graphql] versions may have different capabilities and behavior. The data from one
[graphql] version used in the function from another could produce confusing and
[graphql] spurious results.
[graphql]     Error: Cannot use GraphQLNonNull "String!" from another module or realm.
[graphql]
[graphql]     Ensure that there is only one instance of "graphql" in the node_modules
[graphql]     directory. If different versions of "graphql" are the dependencies of
[graphql]     other
[graphql]     relied on modules, use "resolutions" to ensure only one version is
[graphql]     installed.
[graphql]
[graphql]     https://yarnpkg.com/en/docs/selective-version-resolutions
[graphql]
[graphql]     Duplicate "graphql" modules cannot be used at the same time since
[graphql]     different
[graphql]     versions may have different capabilities and behavior. The data from one
[graphql]     version used in the function from another could produce confusing and
[graphql]     spurious results.
[graphql] The script called "graphql.download" which runs "apollo client:download-schema -c src/services/shopify/apollo.config.js src/services/shopify/schema.gql" failed with exit code 2 https://github.com/sezna/nps/blob/master/other/ERRORS_AND_WARNINGS.md#failed-with-exit-code
[graphql] The script called "graphql" which runs "nps graphql.download && nps "graphql.codegen --watch"" failed with exit code 2 https://github.com/sezna/nps/blob/master/other/ERRORS_AND_WARNINGS.md#failed-with-exit-code
[graphql] nps graphql exited with code 2
--> Sending SIGTERM to other processes..
[next] nps next exited with code 1

You can see that there is one additional version of graphql as a dependency of apollo-language-server:

$ npm list graphql
[email protected] C:\Users\rhysv\Projects\next-shopify-storefront
โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ @n1ru4l/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚   โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚   โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ @graphql-tools/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ @graphql-codegen/[email protected]
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ @apollo/[email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ @apollographql/[email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @apollographql/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @apollographql/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ @apollographql/[email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚   โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ””โ”€โ”€ [email protected] deduped
โ””โ”€โ”€ [email protected]

Not sure if I'm on the right path above, but it's a non-starter for me regardless.

CommanJS error and redux select issue

I have some issues with this setup, one of them are:

[ error ] ERROR in components/Layout/AppBar.tsx(63,48):
63:48 Property 'checkout' does not exist on type 'DefaultRootState'.
    61 | 
    62 | function PrimaryAppBar() {
  > 63 |   const totalQuantity: number = useSelector(({ checkout }) => {
       |                                                ^
    64 |     let totalQuantity = 0;
    65 | 
    66 |     if (checkout.data) {
.next/server/ssr-module-cache.js:3:7 - error TS1208: Cannot compile namespaces when the '--isolatedModules' flag is provided.

3       module.exports = {}
        ~~~~~~

And it complaing alot about require .

How Do I Handle Typesafe Modular Data Fetching in Next.js?

Challenge

During the development cycle, we constantly add new features, fix bugs and refactor the code to improve readability and performance. And with many developers working on one project, moving fast and breaking nothing could be a challenge. In this article, I am going to share with you how I handle data fetching safely, and modularly in Next.js projects to solve this challenge.

Solution

When we do data fetching in Next.js, we tend to put all our code inside getServerSideProps or getStaticProps, and then we pass the data down to the component tree. However, this approach makes it hard to reuse our code on different pages.

Instead, I suggest we should split our pages into modular sections. Each section file has its UI component and its data fetching function. So we can reuse a section on many pages without rewriting data fetching code and reimplementing data types.

To simplify the process, I have created an npm package called @maxvien/next. This package includes some functions and type utilities that could help implement my approach cleaner.

Define a Modular Section

A modular section has two things. One is the Component for building UI. One is the Data Fetching Function for the Component.

To quickly create the props type for the Component, we use the DataProps utility. The DataProps utility will take the return type of the Data Fetching Function and assign it to the data prop as you can see below.

import { DataProps } from '@maxvien/next';

// Data Fetching Function
export async function fetchExampleSection(id: string) {
  const person = await getPersonFromApi(id);

  return person as { name: string; age: number };
}

// Component
export function ExampleSection(props: DataProps<typeof fetchExampleSection>) {
  return (
    <section>
      <h1>Person</h1>
      <p>Name: {props.data.name}</p>
      <p>Age: {props.data.age}</p>
    </section>
  );
}

Thanks to the benefit of tree shacking, Webpack will remove the fetchExampleSection function from the client bundle, so you don't need to be worried about including your server code on browsers. Because we don't use the function directly in the Component.

If Webpack fires errors when you use Node.js modules like fs, you should put some lines of code into package.json like below to tell Webpack to exclude modules from the client bundle.

"browser": {
  "fs": false
}

Use a Modular Section

For data fetching, instead of defining a normal function, we use utility functions like fetchServerSideProps, fetchStaticProps, and fetchStaticPaths from the @maxvien/next package. These functions will help the PageProps utility to take the return type of the data fetching functions and assign it to the page props as you can see below.

import { fetchStaticProps, PageProps } from '@maxvien/next';
import { ExampleSection, fetchExampleSection } from '../sections/ExampleSection';

export const getStaticProps = fetchStaticProps(async ({ params }) => {
  const id = params?.id as string;

  return {
    props: {
      data: {
        exampleSection: await fetchExampleSection(id),
      },
    },
  };
});

export default function Page(props: PageProps<typeof getStaticProps>) {
  return <ExampleSection data={props.data.exampleSection}></ExampleSection>;
}

You can find real implementations here: https://github.com/maxvien/next-shopify-storefront/tree/v3/src/pages/products

Conclusion

That is how I handle typesafe modular data fetching in Next.js. I hope my little solution can help you add new features, fix bugs and refactor your code more safely throughout the development cycle. Thank you for reading!

Using GraphQL Code Generator to regenerate models for TypeScript

Hi,

I added priceRange to the graphql query on product.service.ts

priceRange { minVariantPrice { amount currencyCode } maxVariantPrice { amount currencyCode } }

and now it throws an error saying that "priceRange does not exist on type 'ProductFragment'"

I found that the generated Shopify models do not have priceRange on them.

I am not very familiar with "GraphQL Code Generator " and would like to know what is the best way in this project to re-generate those models?

Thanks!

Missing files

Hi, I'm trying to install this repo, but haven't had luck. The node version I'm trying to use is 14.15.4.
Which node version are you using?
Can you please upload the package-lock.json?

Asking because I'm unsure that my versions match your versions.

Thanks :)

How Do I Interact Safely with GraphQL API in Next.js?

Challenge

Inconsistent API integrations could lead to data loss or even application crashes. In this article, I am going to share with you how I interact safely with GraphQL API in Next.js.

Solution

The answer to this challenge is using GraphQL Code Generators to create TypeScript clients from GraphQL schemas and GraphQL operations. When the schema from the server changes, we can create a new TypeScript client with a single command.
And thanks to the power of TypeScript, we can spot where to update our code immediately by running the TypeScript compiler.

Choose a GraphQL Code Generator

There are many code generators out there, such as graphql-codegen, graphql-zeus, genql, gqless, etc. Each one has its advantages and disadvantages.

I have had working experience with graphql-codegen since 2019 in Version 1 and Version 2 of the Next Shopify Storefront project. In my opinion, graphql-codegen is super reliable; the only drawback is you must write queries and mutations in pure GraphQL to create TypeScript clients.

The other choices are graphql-zeus, genql. I have worked with both of them on my private projects, along with hasura graphql engine. The advantage of them is you don't need to write GraphQL code to generate TypeScript clients. Instead, you need to write queries and mutations in TypeScript to interact with GraphQL servers.

To simplify the way I interact with GraphQL APIs, I prefer to use graphql-zeus over graphql-codegen. graphql-zeus is also better than genql when it comes to bundle size. You can find my comparison here: https://github.com/maxvien/shopify-graphql-zeus-vs-genql

Create a TypeScript Client with GraphQL Zeus

Now I will show you how I create a TypeScript client from Shopify Storefront GraphQL API with GraphQL Zeus.

First, we need an apiEndpoint and an accessToken from Shopify. In this article, I will use the available API information below. You can follow the Shopify storefront documentation to get yours.

const apiEndpoint = 'https://graphql.myshopify.com/api/2023-01/graphql.json';
const accessToken = 'dd4d4dc146542ba7763305d71d1b3d38';

Next, we will install graphql-zeus in our Next.js project with TypeScript support.

npm install --save-dev graphql-zeus

And with the API information above, we can run this command to create our TypeScript client inside ./src/utilities/storefront.

npx zeus https://graphql.myshopify.com/api/2023-01/graphql.json ./src/utilities/storefront --header=X-Shopify-Storefront-Access-Token:dd4d4dc146542ba7763305d71d1b3d38

In the ./src/utilities/storefront folder, we create a index.ts file like this to configure our client.

import { Thunder } from './zeus';

const apiEndpoint = 'https://graphql.myshopify.com/api/2023-01/graphql.json';
const accessToken = 'dd4d4dc146542ba7763305d71d1b3d38';

const chain = Chain(apiEndpoint, {
  headers: {
    'Content-Type': 'application/json'
    'X-Shopify-Storefront-Access-Token': accessToken,
  },
});

export const storefront = {
  query: chain('query'),
  mutation: chain('mutation'),
};

export * from './zeus';

In case, you want to implement GraphQL Zeus with Shopify Hydrogen React you can follow my configurations here: codegen.mjs, src/utilities/storefront/index.ts.

Write GraphQL Operations with GraphQL Zeus

Now we can use our client to write queries and mutations safely with TypeScript. It will take a little time to familiar with writing GraphQL operations in TypeScript. But it is worth it! It improves your development experience with GraphQL.

import { storefront } from "../utilities/storefront";

const { products } = await storefront.query({
  products: [
    { first: 12 },
    {
      pageInfo: {
        hasNextPage: true,
      },
      edges: {
        cursor: true,
        node: {
          handle: true,
          title: true,
          priceRange: {
            minVariantPrice: {
              amount: true,
              currencyCode: true,
            },
          },
          featuredImage: {
            url: [{ transform: { maxWidth: 500 } }, true],
            altText: true,
            width: true,
            height: true,
          },
        },
      },
    },
  ],
});

console.log(products);

Conclusion

That is how I handle GraphQL API integrations in Next.js. I hope my little solution can help you consume GraphQL API more safely throughout the development cycle. Thank you for reading!

TypeError: Cannot assign to read only property '__esModule' of object '#<Object>'

On a freshly cloned copy, I've ran npm install then npm run dev and I'm getting this error:

TypeError: Cannot assign to read only property '__esModule' of object '#<Object>'
    at OMMITED/next-shopify-storefront/node_modules/apollo-boost/lib/bundle.cjs.js:127:74
    at Array.forEach (<anonymous>)
    at Object.<anonymous> (OMMITED/next-shopify-storefront/node_modules/apollo-boost/lib/bundle.cjs.js:127:36)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.apollo-boost (OMMITED/next-shopify-storefront/.next/server/static/development/pages/webpack:/external "apollo-boost":1:1)
    at __webpack_require__ (OMMITED/next-shopify-storefront/.next/server/static/development/pages/webpack:/webpack/bootstrap:21:1)
    at Module../services/checkout.service.ts (OMMITED/next-shopify-storefront/.next/server/static/development/pages/_app.js:2455:70)
    at __webpack_require__ (OMMITED/next-shopify-storefront/.next/server/static/development/pages/webpack:/webpack/bootstrap:21:1)
    at Module../services/index.ts (OMMITED/next-shopify-storefront/.next/server/static/development/pages/webpack:/services/index.ts:1:1)
    at __webpack_require__ (OMMITED/next-shopify-storefront/.next/server/static/development/pages/webpack:/webpack/bootstrap:21:1)

How Do I Organize a Sustainable Next.js Project?

Challenge

Bad Next.js project organization can lead to problems, such as poor performance, unscalable, unmaintainable, hard to navigate between files, etc. So, in this article, I will share with you how I organize a sustainable Next.js project to improve the development experience.

Solution

I have built a Shopify theme from scratch. I love the clear and maintainable project structure from it. It influences me on how to organize my projects. And just like a Shopify theme, I have several folders like these:

  • Pages: Each page has a layout. Each page can have many sections as needed. For example, a product detail page can have three sections: A product information section, a related products section, and a recommended products section.
  • Layouts: A layout is a reusable component. We can use a layout on many pages. A layout can have a header, a footer, and many child sections.
  • Sections: To me, a section is very important. A section file has its UI component and its data fetching function. So we can reuse a section on many pages without rewriting data fetching code. I also created an npm package called @maxvien/next to handle typesafe modular data fetching in Next.js.
  • Snippets: A snippet is a reusable atomic component. We can use a snippet in pages, layouts, and sections.
  • Assets: The assets folder contains static resources like CSS files, images, fonts, etc.
  • Utilities: The utilities folder includes reusable functions, hooks, services, types, etc.

Now, you have an overview of how I organize a Next.js project. In the next section, I am going to show you in detail.

Project Folders

Look at the folder structure below, you can see that I have src in the root level of the project. So I can separate the source code from the other parts of the project.

  • src
    • assets
    • layouts
    • pages
    • sections
    • snippets
    • utilities

Wrapping the other folders into one src folder makes the project less chaotic. You can look at a real folder structure here: https://github.com/maxvien/next-shopify-storefront/tree/v3/src

Absolute Imports

Using relative imports like this import mod from '../../../mod.ts' makes it hard to identify the locations of the imported files. So, using absolute imports is a better choice. And these are what absolute imports look like.

import '@site/assets/style.css';

import { StoreLayout } from '@site/layouts/StoreLayout';

import { ProductListSection, fetchProductListSection } from '@site/sections/ProductListSection';

import { Button } from '@site/snippets/Button';

import { DataProps, useVariantSelector } from '@site/utilities/deps';

To enable absolute imports, you must create Next.js projects with TypeScript.

npx create-next-app@latest --typescript

Next, in the tsconfig.json file, I will add these lines in the compiler options.

{
  "compiler options": {
    ...
    "baseUrl": ".",
    "paths": {
      "@site/*": ["./src/*"]
    }
  },
 ...
}

You can also take a look at the full file here: https://github.com/maxvien/next-shopify-storefront/blob/v3/tsconfig.json

Conclusion

Good Next.js project organization should be scalable, maintainable, easy to navigate between files, etc. I hope my little solution can improve your development experience. Thank you for reading!

How Do I Implement Dynamic Variant Selector for Shopify in Next.js?

Challenge

Building the UI/UX for a dynamic product options selector for Shopify could be difficult if you try to code it from scratch. In this article, I will show you how to build flexible UI/UX for this feature for your e-commerce site.

Solution

The answer to this challenge is in the @maxvien/shopify npm package. I aimed to create a general-purpose React hook to implement a customizable UI for the product variant selecting feature. So I can use select elements or even button elements to build the UI in the code examples below.

npm install --save-dev @maxvien/shopify

Use Variant Selector React Hook

First, we must query the product data from a Shopify Storefront API. And the return data must satisfy the type below; so we can use it with the useVariantSelector hook.

interface Product {
  variants: {
    nodes: {
      id: string;
      availableForSale: boolean;
      selectedOptions: {
        name: string;
        value: string;
      }[];
    }[];
  };
  options: {
    name: string;
    values: string[];
  }[];
}

Next, we can use the product data with the useVariantSelector hook like the code below.

const { options, selectOption, variantId } = useVariantSelector(product);
  • options is an array that useVariantSelector takes from the product data to help us render the options with button elements or select elements.
  • selectOption is a function that helps us to select an option and store it in the useVariantSelector's state.
  • variantId: If the options we select that match with a variant in the product data, the useVariantSelector will return it as the variantId. And we can use the variantId to add the product variant to the cart.

Implement the Hook with Button Elements

import { useVariantSelector } from '@maxvien/shopify';

export function ProductSingleSection(props: Props) {
  const { variantId, options, selectOption } = useVariantSelector(props.product);

  return (
    <section>
      <div>
        {options.map(({ name, values }) => (
          <div key={name}>
            <h3>{name}</h3>

            {values.map(({ value, selected, disabled }) => {
              return (
                <button
                  key={value}
                  disabled={disabled}
                  style={{ background: selected ? 'yellow' : 'inherit' }}
                  onClick={() => selectOption(name, value)}
                >
                  {value}
                </button>
              );
            })}
          </div>
        ))}
      </div>

      <button disabled={!!variantId} onClick={() => addTocart(variantId)}>
        Add to Cart
      </button>
    </section>
  );
}

Implement the Hook with Select Elements

import { useVariantSelector } from '@maxvien/shopify';

export function ProductSingleSection(props: Props) {
  const { variantId, options, selectOption } = useVariantSelector(props.product);

  return (
    <section>
      <div>
        {options.map(({ name, values }) => {
          return (
            <div key={name}>
              <h3>{name}</h3>

              <select onChange={(event) => selectOption(name, event.target.value)}>
                <option value="">Choose {name}</option>
                {values.map(({ value, disabled, selected }) => (
                  <option key={value} value={value} selected={selected} disabled={disabled}>
                    {value}
                  </option>
                ))}
              </select>
            </div>
          );
        })}
      </div>

      <button disabled={!!variantId} onClick={() => addTocart(variantId)}>
        Add to Cart
      </button>
    </section>
  );
}

Conclusion

That is how I implement dynamic variant selectors for Shopify in Next.js. I hope my little solution can help you increase your conversion rate by building effective UI/UX for your product pages. Thank you for reading!

Boost Your Shopify Storefront API Integration with the Headless App

Hey everyone,

I have some exciting news to share! If you're using platforms like Vercel, AWS, or others with Shopify's Storefront API, there's a solution called the Headless app available in the Shopify App Store. By installing this app, you can say goodbye to limits that might be imposed on these platforms.

When you install the Headless app, you'll be able to get both a "Public access token" and a "Private access token." It's just like when you install the Hydrogen app.

However, I want to clarify that if you choose to create a private app to access the storefront API information, you won't get a "Private access token" like you would with the Headless app.

I hope this information helps you understand how the Headless app can unlock the full potential of the Storefront API on different platforms. If you have any questions or need assistance, feel free to ask.

Enjoy exploring the possibilities, and happy integrating!

Best regards,
Vien

Support for collections

Hi ๐Ÿ‘‹

Thanks a lot for building such an amazing project. Saved me a lot of time. I'm wondering if you're interested in adding support for collections. I've implemented it in my own fork, and if you're interested, I'd be happy to port it back to this repo.

The way I implemented it is by adding another button in the toolbar beside the Products button, called Collections. Clicking on that button, you'll get a paginated list of collections (in the same card format of product, just without a price). When you click on any of the collections, you'll get the list of products inside this collection (reusing the product list page).

Let me know if you're interested.

cant querry

am trying to "npm run dev".. am currently getting this err
status: 1, signal: null, output: [ null, null, null ], pid: 19368, stdout: null, stderr: null }
im pretty sure my .env is set up correctly.

internal/modules/cjs/loader.js:985 throw err;

Thank you for putting this great demo out there! Unfortunately, I can't run it locally, I get this error:

> [email protected] start /Users/david/Dev/next-shopify-storefront
> NODE_ENV=production node dist/index.js

internal/modules/cjs/loader.js:985
  throw err;
  ^

Error: Cannot find module '/Users/david/Dev/next-shopify-storefront/dist/index.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:982:15)
    at Function.Module._load (internal/modules/cjs/loader.js:864:27)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `NODE_ENV=production node dist/index.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/david/.npm/_logs/2020-04-19T11_29_46_239Z-debug.log
David:next-shopify-storefront david$ 

Using Node v12.16.1 & Npm v6.13.4 if that's relevant.

Any ideas? :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.