/shopify-app-template-react-router

An template for building Shopify Apps using React Router v7 and above

Primary LanguageTypeScriptMIT LicenseMIT

Shopify App Template - React Router

This is a template for building a Shopify app using React Router. It was forked from the Shopify Remix app template and converted to React Router.

Rather than cloning this repo, follow the Quick Start steps.

Visit the shopify.dev documentation for more details on the React Router app package.

Upgrading from Remix

If you have an existing Remix app that you want to upgrade to React Router, please follow the upgrade guide. Otherwise, please follow the quick start guide below.

Quick start

Prerequisites

Before you begin, you'll need the following:

  1. Node.js: Download and install it if you haven't already.
  2. Shopify Partner Account: Create an account if you don't have one.
  3. Test Store: Set up either a development store or a Shopify Plus sandbox store for testing your app.
  4. Shopify CLI: Download and install it if you haven't already.
npm install -g @shopify/cli@latest

Setup

shopify app init --template=https://github.com/Shopify/shopify-app-template-react-router

Local Development

shopify app dev

Press P to open the URL to your app. Once you click install, you can start development.

Local development is powered by the Shopify CLI. It logs into your partners account, connects to an app, provides environment variables, updates remote config, creates a tunnel and provides commands to generate extensions.

Authenticating and querying data

To authenticate and query data you can use the shopify const that is exported from /app/shopify.server.js:

export async function loader({ request }) {
  const { admin } = await shopify.authenticate.admin(request);

  const response = await admin.graphql(`
    {
      products(first: 25) {
        nodes {
          title
          description
        }
      }
    }`);

  const {
    data: {
      products: { nodes },
    },
  } = await response.json();

  return nodes;
}

This template comes pre-configured with examples of:

  1. Setting up your Shopify app in /app/shopify.server.ts
  2. Querying data using Graphql. Please see: /app/routes/app._index.tsx.
  3. Responding to webhooks. Please see /app/routes/webhooks.tsx.

Please read the documentation for @shopify/shopify-app-react-router to see what other API's are available.

Deployment

Application Storage

This template uses Prisma to store session data, by default using an SQLite database. The database is defined as a Prisma schema in prisma/schema.prisma.

This use of SQLite works in production if your app runs as a single instance. The database that works best for you depends on the data your app needs and how it is queried. Here’s a short list of databases providers that provide a free tier to get started:

Database Type Hosters
MySQL SQL Digital Ocean, Planet Scale, Amazon Aurora, Google Cloud SQL
PostgreSQL SQL Digital Ocean, Amazon Aurora, Google Cloud SQL
Redis Key-value Digital Ocean, Amazon MemoryDB
MongoDB NoSQL / Document Digital Ocean, MongoDB Atlas

To use one of these, you can use a different datasource provider in your schema.prisma file, or a different SessionStorage adapter package.

Build

Build the app by running the command below with the package manager of your choice:

Using yarn:

yarn build

Using npm:

npm run build

Using pnpm:

pnpm run build

Hosting

When you're ready to set up your app in production, you can follow our deployment documentation to host your app on a cloud provider like Heroku or Fly.io.

When you reach the step for setting up environment variables, you also need to set the variable NODE_ENV=production.

Gotchas / Troubleshooting

Database tables don't exist

If you get an error like:

The table `main.Session` does not exist in the current database.

Create the database for Prisma. Run the setup script in package.json using npm, yarn or pnpm.

Navigating/redirecting breaks an embedded app

Embedded apps must maintain the user session, which can be tricky inside an iFrame. To avoid issues:

  1. Use Link from react-router or @shopify/polaris. Do not use <a>.
  2. Use redirect returned from authenticate.admin. Do not use redirect from react-router
  3. Use useSubmit from react-router.

This only applies if your app is embedded, which it will be by default.

App goes into a loop when I change my app's scopes

If you change your app's scopes and authentication goes into a loop before failing after trying too many times, you might have forgotten to update your scopes with Shopify. Update your scopes.

Using yarn:

yarn deploy

Using npm:

npm run deploy

Using pnpm:

pnpm run deploy

Webhooks: shop-specific webhook subscriptions aren't updated

If you are registering webhooks in the afterAuth hook, using shopify.registerWebhooks, you may find that your subscriptions aren't being updated.

Instead of using the afterAuth hook declare app-specific webhooks in the shopify.app.toml file. This approach is easier since Shopify will automatically sync changes every time you run deploy (e.g: npm run deploy). Please read these guides to understand more:

  1. app-specific vs shop-specific webhooks
  2. Create a subscription tutorial

If you do need shop-specific webhooks, keep in mind that the package calls afterAuth in 2 scenarios:

  • After installing the app
  • When an access token expires

During normal development, the app won't need to re-authenticate most of the time, so shop-specific subscriptions aren't updated. To force your app to update the subscriptions, uninstall and reinstall the app. Revisiting the app will call the afterAuth hook.

Webhooks: Admin created webhook failing HMAC validation

Webhooks subscriptions created in the Shopify admin will fail HMAC validation. This is because the webhook payload is not signed with your app's secret key.

The recommended solution is to use app-specific webhooks defined in your toml file instead. Test your webhooks by triggering events manually in the Shopify admin(e.g. Updating the product title to trigger a PRODUCTS_UPDATE).

Webhooks: Admin object undefined on webhook events triggered by the CLI

When you trigger a webhook event using the Shopify CLI, the admin object will be undefined. This is because the CLI triggers an event with a valid, but non-existent, shop. The admin object is only available when the webhook is triggered by a shop that has installed the app. This is expected.

Webhooks triggered by the CLI are intended for initial experimentation testing of your webhook configuration. For more information on how to test your webhooks, see the Shopify CLI documentation.

Incorrect GraphQL Hints

By default the graphql.vscode-graphql extension for will assume that GraphQL queries or mutations are for the Shopify Admin API. This is a sensible default, but it may not be true if:

  1. You use another Shopify API such as the storefront API.
  2. You use a third party GraphQL API.

If so, please update .graphqlrc.ts.

Using Defer & await for streaming responses

By default the CLI uses a cloudflare tunnel. Unfortunately cloudflare tunnels wait for the Response stream to finish, then sends one chunk. This will not affect production.

To test streaming using await during local development we recommend localhost based development.

Using MongoDB and Prisma

By default this template uses SQLlite as the database. It is recommended to move to a persisted database for production. If you choose to use MongoDB, you will need to make some modifications to the schema and prisma configuration. For more information please see the Prisma MongoDB documentation.

Alternatively you can use a MongDB database directly with the MongoDB session storage adapter.

Mapping the id field

In MongoDB, an ID must be a single field that defines an @id attribute and a @map("\_id") attribute. The prisma adapter expects the ID field to be the ID of the session, and not the _id field of the document.

To make this work add a new field to the schema that maps the _id field to the id field. For more information see the Prisma documentation

model Session {
  session_id  String    @id @default(auto()) @map("_id") @db.ObjectId
  id          String    @unique
...
}

Error: The "mongodb" provider is not supported with this command

MongoDB does not support the prisma migrate command. Instead, you can use the prisma db push command and update the shopify.web.toml file with the following commands. If you are using MongoDB please see the Prisma documentation for more information.

[commands]
predev = "npx prisma generate && npx prisma db push"
dev = "npx prisma migrate deploy && npm exec react-router dev"

Prisma needs to perform transactions, which requires your mongodb server to be run as a replica set

See the Prisma documentation for connecting to a MongoDB database.

"nbf" claim timestamp check failed

This is because a JWT token is expired. If you are consistently getting this error, it could be that the clock on your machine is not in sync with the server. To fix this ensure you have enabled "Set time and date automatically" in the "Date and Time" settings on your computer.

Resources

React Router:

Shopify:

Internationalization: