shopify-remix-template
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseShopify Remix Template Guide
Shopify Remix 模板指南
This skill provides a guide for building Shopify apps using the official Shopify Remix App Template. This template is the recommended starting point for most new Shopify embedded apps (though React Router is the future direction, Remix is still widely used and supported).
本指南介绍如何使用官方Shopify Remix App Template构建Shopify应用。该模板是大多数新Shopify嵌入式应用的推荐起步方案(尽管React Router是未来发展方向,但Remix目前仍被广泛使用和支持)。
🚀 Getting Started
🚀 快速开始
To create a new app using the Remix template, run:
bash
git clone https://github.com/Shopify/shopify-app-template-remix.git要使用Remix模板创建新应用,请运行:
bash
git clone https://github.com/Shopify/shopify-app-template-remix.git📂 Project Structure
📂 项目结构
A typical Remix app structure:
app/- : File-system based routing.
routes/- : The main dashboard page.
app._index.tsx - : The root layout for the authenticated app.
app.tsx - : Webhook handler.
webhooks.tsx
- : Critical. Initializes the Shopify API client, authentication, and session storage (Redis).
shopify.server.ts - : Database connection (Mongoose).
db.server.ts - : Mongoose models (e.g.,
models/,Session.ts).Shop.ts - : The root component for the entire application.
root.tsx
- : Main app configuration file.
shopify.app.toml
典型的Remix应用结构:
app/- : 基于文件系统的路由。
routes/- : 主仪表盘页面。
app._index.tsx - : 已认证应用的根布局。
app.tsx - : Webhook处理器。
webhooks.tsx
- : 核心文件。初始化Shopify API客户端、认证及会话存储(Redis)。
shopify.server.ts - : 数据库连接(Mongoose)。
db.server.ts - : Mongoose模型(例如
models/、Session.ts)。Shop.ts - : 整个应用的根组件。
root.tsx
- : 应用主配置文件。
shopify.app.toml
🔐 Authentication & Sessions
🔐 认证与会话
The template uses to handle authentication automatically.
@shopify/shopify-app-remix该模板使用自动处理认证。
@shopify/shopify-app-remixshopify.server.ts
shopify.server.tsshopify.server.ts
shopify.server.tsThis file exports an object used in loaders and actions. It is configured to use Redis for session storage.
authenticatetypescript
import { shopifyApp } from "@shopify/shopify-app-remix/server";
import { RedisSessionStorage } from "@shopify/shopify-app-session-storage-redis";
const sessionDb = new RedisSessionStorage(
new URL(process.env.REDIS_URL!)
);
const shopify = shopifyApp({
apiKey: process.env.SHOPIFY_API_KEY,
apiSecretKey: process.env.SHOPIFY_API_SECRET,
appUrl: process.env.SHOPIFY_APP_URL,
scopes: process.env.SCOPES?.split(","),
apiVersion: "2025-10",
sessionStorage: sessionDb,
isEmbeddedApp: true,
});
export const authenticate = shopify.authenticate;
export const apiVersion = "2025-10";
export const addDocumentResponseHeaders = shopify.addDocumentResponseHeaders;此文件导出一个对象,用于加载器(loaders)和动作(actions)中。它配置为使用Redis进行会话存储。
authenticatetypescript
import { shopifyApp } from "@shopify/shopify-app-remix/server";
import { RedisSessionStorage } from "@shopify/shopify-app-session-storage-redis";
const sessionDb = new RedisSessionStorage(
new URL(process.env.REDIS_URL!)
);
const shopify = shopifyApp({
apiKey: process.env.SHOPIFY_API_KEY,
apiSecretKey: process.env.SHOPIFY_API_SECRET,
appUrl: process.env.SHOPIFY_APP_URL,
scopes: process.env.SCOPES?.split(","),
apiVersion: "2025-10",
sessionStorage: sessionDb,
isEmbeddedApp: true,
});
export const authenticate = shopify.authenticate;
export const apiVersion = "2025-10";
export const addDocumentResponseHeaders = shopify.addDocumentResponseHeaders;Usage in Loaders (Data Fetching)
在加载器(Loaders)中使用(数据获取)
Protect routes and get the session context:
typescript
import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const loader = async ({ request }) => {
const { admin, session } = await authenticate.admin(request);
// Use admin API
const response = await admin.graphql(`...`);
return json({ data: response });
};保护路由并获取会话上下文:
typescript
import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const loader = async ({ request }) => {
const { admin, session } = await authenticate.admin(request);
// 使用Admin API
const response = await admin.graphql(`...`);
return json({ data: response });
};📡 Webhooks
📡 Webhook
Webhooks are handled in (or individual route files). The template automatically registers webhooks defined in .
app/routes/webhooks.tsxshopify.server.tsTo add a webhook:
- Add configuration in .
shopify.server.ts - Handle the topic in the of
action.app/routes/webhooks.tsx
Webhook在(或单独的路由文件)中处理。模板会自动注册中定义的Webhook。
app/routes/webhooks.tsxshopify.server.ts添加Webhook的步骤:
- 在中添加配置。
shopify.server.ts - 在的
app/routes/webhooks.tsx中处理对应的主题。action
🗄️ Database (Mongoose/MongoDB)
🗄️ 数据库(Mongoose/MongoDB)
Use Mongoose for persistent data storage (Shops, Settings, etc.).
使用Mongoose进行持久化数据存储(店铺、设置等)。
app/db.server.ts
app/db.server.tsapp/db.server.ts
app/db.server.tsSingleton connection to MongoDB.
typescript
import mongoose from "mongoose";
let isConnected = false;
export const connectDb = async () => {
if (isConnected) return;
try {
await mongoose.connect(process.env.MONGODB_URI!);
isConnected = true;
console.log("🚀 Connected to MongoDB");
} catch (error) {
console.error("❌ MongoDB connection error:", error);
}
};MongoDB的单例连接。
typescript
import mongoose from "mongoose";
let isConnected = false;
export const connectDb = async () => {
if (isConnected) return;
try {
await mongoose.connect(process.env.MONGODB_URI!);
isConnected = true;
console.log("🚀 Connected to MongoDB");
} catch (error) {
console.error("❌ MongoDB connection error:", error);
}
};app/models/Shop.ts
(Example)
app/models/Shop.tsapp/models/Shop.ts
(示例)
app/models/Shop.tstypescript
import mongoose from "mongoose";
const ShopSchema = new mongoose.Schema({
shop: { type: String, required: true, unique: true },
accessToken: { type: String, required: true },
isInstalled: { type: Boolean, default: true },
});
export const Shop = mongoose.models.Shop || mongoose.model("Shop", ShopSchema);typescript
import mongoose from "mongoose";
const ShopSchema = new mongoose.Schema({
shop: { type: String, required: true, unique: true },
accessToken: { type: String, required: true },
isInstalled: { type: Boolean, default: true },
});
export const Shop = mongoose.models.Shop || mongoose.model("Shop", ShopSchema);Usage in Loaders
在加载器中使用
Connect to the DB before using models.
typescript
import { connectDb } from "../db.server";
import { Shop } from "../models/Shop";
export const loader = async ({ request }) => {
await connectDb();
// ...
const shopData = await Shop.findOne({ shop: session.shop });
// ...
};使用模型前先连接数据库。
typescript
import { connectDb } from "../db.server";
import { Shop } from "../models/Shop";
export const loader = async ({ request }) => {
await connectDb();
// ...
const shopData = await Shop.findOne({ shop: session.shop });
// ...
};🎨 UI & Design (Polaris)
🎨 UI与设计(Polaris)
The template comes pre-configured with Polaris, Shopify's design system.
- Wrap your pages in components.
<Page> - Use ,
<Layout>, and other Polaris components for a native feel.<Card> - App Bridge is initialized automatically in .
app.tsx
该模板预先配置了Polaris(Shopify的设计系统)。
- 用组件包裹页面。
<Page> - 使用、
<Layout>等Polaris组件,实现原生Shopify风格。<Card> - App Bridge会在中自动初始化。
app.tsx
🛠️ Common Tasks
🛠️ 常见任务
1. Adding a Navigation Item
1. 添加导航项
Update :
app/routes/app.tsxtypescript
<ui-nav-menu>
<Link to="/app">Home</Link>
<Link to="/app/settings">Settings</Link>
</ui-nav-menu>更新:
app/routes/app.tsxtypescript
<ui-nav-menu>
<Link to="/app">Home</Link>
<Link to="/app/settings">Settings</Link>
</ui-nav-menu>2. Fetching Data from Shopify
2. 从Shopify获取数据
Use the object from to make GraphQL calls.
adminauthenticate.admin(request)使用返回的对象发起GraphQL调用。
authenticate.admin(request)admin3. Deploying
3. 部署
- Hosting: Remix apps can be hosted on Vercel, Fly.io, Heroku, or Cloudflare.
- Database: Ensure you have a persistent database (e.g., Postgres) for production.
- Environment Variables: Set ,
SHOPIFY_API_KEY,SHOPIFY_API_SECRET,SCOPES.SHOPIFY_APP_URL
- 托管:Remix应用可托管在Vercel、Fly.io、Heroku或Cloudflare上。
- 数据库:生产环境需使用持久化数据库(例如Postgres)。
- 环境变量:设置、
SHOPIFY_API_KEY、SHOPIFY_API_SECRET、SCOPES。SHOPIFY_APP_URL