import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const loader = async ({ request }: LoaderFunctionArgs) => {
const { admin, session, billing } = await authenticate.admin(request);
// Verifică planul înainte de render
const hasPayment = await billing.check({
plans: ["PRO_MONTHLY_PLAN"],
isTest: process.env.NODE_ENV !== "production",
});
if (!hasPayment.hasActivePayment) {
await billing.request({
plan: "PRO_MONTHLY_PLAN",
isTest: process.env.NODE_ENV !== "production",
returnUrl: `https://${session.shop}/admin/apps/${process.env.APP_NAME}`,
});
}
// Query GraphQL optimizat prin clientul admin
const response = await admin.graphql(`
query getShopDetails {
shop {
name
currencyCode
}
}
`);
const { data } = await response.json();
return json({ shop: data.shop });
};Dacă vrei să publici un app în Shopify App Store în 2024, stack-ul oficial recomandat e @shopify/shopify-app-remix legat cu Polaris și App Bridge. Pare simplu din template-ul de CLI, dar când trimiți app-ul la echipa de review de la Shopify, te lovești de standarde stricte de UX și auth.
Am lansat recent un app de loyalty care a ajuns la 450 de magazine active. La prima trimitere am fost respins în mai puțin de 4 ore. La a treia a trecut cu brio. Iată ce am învățat pe pielea mea despre setup și ce verifică reviewerii umani.
De ce Remix + Polaris și unde doare
Template-ul oficial pe Remix se mișcă excelent fiindcă rulează Node sau Cloudflare Workers și gestionează automat session tokens prin App Bridge. Nu mai scrii tu logica de handshake cu iframe-ul cum făceam acum 4 ani pe Express.
Polaris oferă componente native identice cu Shopify Admin. Reviewerii vor ca magazinul să nu simtă diferența între setările din Shopify și app-ul tău.
Trade-off-ul sincer? Polaris e rigid ca o scândură. Dacă vrei un dashboard cu grafice ultra-customizate sau layout-uri non-standard, te lupți cu CSS-ul lor și risti să strici dark mode-ul nativ din admin. Dacă folosești Tailwind direct peste componentele lor, e o ciorbă greu de întreținut.
Unde am picat la review (și cum eviți asta)
Echipa de review testează app-ul ca un comerciant grăbit și ignorat. Nu le pasă cât de curat e codul tău din backend, ci cum se comportă UI-ul în cazuri limită:
- Empty states inexistente: Dacă un magazin abia a instalat app-ul și nu are date, nu lăsa un tabel gol sau un ecran alb. Trebuie să ai componenta
<EmptyState>de la Polaris cu un Call to Action clar. - Billing API netratat corect: Dacă app-ul tău are plan plătit, trebuie să redirecționezi folosind
billing.requestdin SDK-ul de Remix. Dacă redirecționezi cu unwindow.locationclasic sau faci iframe breakout incorect, pică instant. - Test pe mobil în aplicația Shopify: Reviewerul deschide app-ul din aplicația de iOS/Android a Shopify. Dacă ai un tabel orizontal fără scroll dedicat sau butoane care ies din ecran, primești respingere cu captură de ecran video atașată.
- Session Token expirat la background tab: Când lași tab-ul deschis 2 ore și te întorci, un fetch simplu crapă cu 401 dacă nu trece prin fetch-ul wrappuit de App Bridge.
Pattern util pentru billing și auth în loader
În fiecare route protejată din Remix, trebuie să validezi autentificarea magazinului și statusul abonamentului înainte de a randa componentele Polaris. Altfel, utilizatorul vede un flash de conținut înainte de redirect.