Coding patterns for Shopify embedded admin app. Auto-apply when writing Remix routes, Polaris components, App Bridge interactions, or admin UI code in app/ directory.
3f:Te16,
Áp dụng conventions này khi develop code trong admin app (Remix + Polaris + App Bridge 4.x).
| Layer | Technology | Notes |
|---|---|---|
| Framework | Remix (Shopify App Template) | SSR, loader/action pattern |
| UI | Polaris React | Shopify design system, KHÔNG custom CSS trừ khi bắt buộc |
| Navigation | App Bridge 4.x | Embedded app navigation, modals, toasts |
| Language | TypeScript (strict mode) | No any, prefer unknown + type guards |
| State | Remix loaders/actions | Server-first, minimize client state |
| Auth | Shopify session tokens | Via authenticate.admin() |
loader, mutations trong action — KHÔNG fetch từ client trừ khi realtimeErrorBoundary componentSkeletonPage / SkeletonBodyText cho loadingapp/
├── routes/
│ ├── app._index.tsx # Dashboard / landing
│ ├── app.settings.tsx # Settings page
│ ├── app.[resource].tsx # Resource list (e.g., app.products.tsx)
│ ├── app.[resource].$id.tsx # Resource detail (e.g., app.orders.$id.tsx)
│ └── app.[resource].new.tsx # Resource create
├── components/ # Shared Polaris components
├── utils/ # Helpers, validators
├── models/ # Prisma model helpers
└── graphql/ # Shopify GraphQL queries/mutations
app. cho tất cả authenticated routes$id cho dynamic params.new suffix cho create pagesXem chi tiết tại patterns.md bao gồm:
// LUÔN authenticate trước khi access admin API
const { admin, session } = await authenticate.admin(request);
// GraphQL query
const response = await admin.graphql(`
#graphql
query GetProducts($first: Int!) {
products(first: $first) {
edges {
node {
id
title
}
}
}
}
`, { variables: { first: 10 } });
authenticate.admin(request) ở đầu mọi loader/actionPage, Layout, Card cho page structureuseNavigation() để show loading statesResponse errors từ Shopify API gracefullyuseAppBridge() cho App Bridge interactionsuseState cho data có thể fetch từ serverfetch() từ client-side cho admin API callswindow.location — dùng App Bridge navigation$ARGUMENTS