Pular para o conteúdo principal

SDK Helper

Apps NubeSDK rodam dentro de um web worker isolado, sem acesso direto ao DOM. Tudo que o app faz: ler o estado, renderizar componentes, navegar e armazenar dados passa pela instância do SDK que o runtime entrega ao ponto de entrada App(nube).

Na prática, essa instância nube acaba sendo passada por todas as funções e componentes do app, e alguns padrões se repetem em todo projeto: ler a página atual, estreitar tipos de página, renderizar um componente por produto, exibir um toast ao receber um evento.

@tiendanube/nube-sdk-helper concentra esses padrões em um conjunto de utilitários pequeno e fortemente tipado.

Instalação

npm install @tiendanube/nube-sdk-helper @tiendanube/nube-sdk-types

@tiendanube/nube-sdk-types é uma peer dependency e deve ser instalada junto.

Registrando a instância

O runtime entrega a instância do SDK apenas como argumento do ponto de entrada. A ideia central do helper é simples: registre uma vez, e todos os outros helpers chegam até ela por conta própria, sem precisar passar nube por toda a árvore do app.

src/App.ts
import {
setNubeInstance,
getCurrentState,
ui,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before anything else

const state = getCurrentState();
ui.showToast(`You are on the ${state.location.page.type} page`);
}

Três funções gerenciam a instância:

  • setNubeInstance(nube): registra a instância (chame uma vez no topo do App).
  • getNubeInstance(): retorna a instância registrada, lançando um erro descritivo se ela ainda não foi registrada.
  • clearNubeInstance(): limpa a instância (útil em testes).

Por que isso importa

Com a instância registrada globalmente, as ações mais comuns viram funções independentes que podem ser chamadas de qualquer lugar: um componente aninhado, um módulo utilitário, um event handler, sem precisar receber nube como parâmetro.

import { navigate, ui } from "@tiendanube/nube-sdk-helper";

// Em qualquer lugar do app, sem `nube` no escopo:
function onCheckoutClick() {
navigate("/checkout"); // routes to the path internally via the SDK instance
ui.showToast("Taking you to checkout...", "info");
}

Sem o helper, seria necessário ter uma referência a nube no escopo e chamar nube.getBrowserAPIs().navigate(...), além de construir o componente de toast manualmente. O helper reduz ambos a uma linha.

O mesmo se aplica ao armazenamento no browser:

import { browser } from "@tiendanube/nube-sdk-helper";

await browser.asyncLocalStorage.setItem("seen-banner", "true");
const seen = await browser.asyncLocalStorage.getItem("seen-banner");

Lendo o estado com seletores

Os seletores seguem um padrão consistente: chamados sem argumento, leem o estado atual do SDK; passando um estado explícito, tornam-se funções puras.

import { getCartItems, getPageType, getCustomer } from "@tiendanube/nube-sdk-helper";

// Sem argumento: lê o estado atual da instância do SDK.
const items = getCartItems();
const pageType = getPageType();
const customer = getCustomer();

// Com estado explícito: puro, ideal para testes unitários.
const itemsFromMock = getCartItems(mockState);
Testabilidade

Passe um estado mock para qualquer seletor e ele se comporta como uma função pura: sem efeitos colaterais, sem depender da instância registrada. Esse padrão vale para toda a família de seletores.

Guards

Guards fazem dupla função: validam em runtime e estreitam o tipo para o TypeScript, desbloqueando os dados específicos da página tipados pelo compilador.

import { getCurrentState, isProductPage } from "@tiendanube/nube-sdk-helper";

const { page } = getCurrentState().location;

if (isProductPage(page)) {
// `page` is now narrowed to a ProductPage, so `page.data.product` is typed.
console.log(page.data.product.name);
}
Validação e tipagem juntos

Diferente de um cast (as ProductPage), os guards verificam a estrutura em runtime antes de estreitar o tipo. Se a condição não passar, o TypeScript não expõe page.data.product.

Há um guard para quase toda estrutura encontrada em um app NubeSDK:

  • Páginas: isProductPage, isCategoryPage, isCheckoutPage, isHomePage, isAllProductsPage, isSearchPage
  • Carrinho: isCart, isCartItem, isCartValidationSuccess, isCartValidationPending, isCartValidationFail
  • Domínio: isStore, isCustomer, isPayment, isShipping, isAddress, e mais
  • Componentes / dados de página: isNubeComponent, hasProductList, hasSections, hasSingleProduct, isSectionWithProducts

Getters

Além dos seletores de estado, os getters expõem os metadados injetados pelo runtime sobre o app. Um exemplo útil é getScriptURL, que analisa a URL de onde o script do app foi carregado (cacheada como uma URL congelada):

import { getScriptURL, getScriptParam } from "@tiendanube/nube-sdk-helper";

const url = getScriptURL();
console.log("Script origin:", url.origin);
console.log("Script pathname:", url.pathname);

// Read configuration passed as query params on the script URL, e.g. ?variant=b
const variant = getScriptParam("variant"); // string | null

Essa é a forma idiomática de configurar um app a partir da tag de script, sem precisar de uma requisição adicional.

Page matching

pageMatch e onPage resolvem o mesmo problema de ângulos diferentes. pageMatch despacha uma vez contra um estado fornecido, e cada handler recebe o payload corretamente tipado para a sua página. onPage envolve pageMatch, mas subscreve à navegação, re-executando a cada mudança de página e retornando uma função de cancelamento.

Use pageMatch para uma decisão pontual com base no estado atual:

import { pageMatch, getCurrentState } from "@tiendanube/nube-sdk-helper";

// Runs once against the state you pass in.
pageMatch(getCurrentState(), {
product: (state, product) => console.log("Product:", product.name),
checkout: (state, checkout) => console.log("Step:", checkout.step),
});

Use onPage para reagir continuamente à navegação do usuário:

import { onPage } from "@tiendanube/nube-sdk-helper";

const stop = onPage({
product: (state, product) => trackProductView(product.id),
checkout: (state, checkout) => {
if (checkout.step === "success") trackPurchase();
},
// category / home handlers are optional
});

// Later, when you no longer need it:
stop();

Para checkout especificamente, onCheckoutStep permite reagir a um step específico:

import { onCheckoutStep } from "@tiendanube/nube-sdk-helper";

onCheckoutStep({
success: () => trackPurchase(),
});

Render

Uma necessidade frequente é renderizar algo em um slot de grade de produto: um badge, um label, um ícone. forEachProduct extrai todos os produtos do estado atual (independentemente do tipo de página), mapeia cada um por uma factory de renderização, descarta resultados vazios e atribui automaticamente um key único a partir do id do produto.

import { getNubeInstance, forEachProduct } from "@tiendanube/nube-sdk-helper";

getNubeInstance().render(
"product_grid_item_image_bottom_right",
forEachProduct((product) => <MyBadge product={product} />),
);

Sem JSX, a factory retorna um objeto de componente diretamente:

getNubeInstance().render(
"product_grid_item_image_bottom_right",
forEachProduct((product) => ({ type: "txt", children: product.name })),
);

Retornar null ou undefined da factory pula o produto: essas entradas são filtradas automaticamente.

Helpers de UI e eventos

ui agrupa as operações de view mais comuns, incluindo renderizar o mesmo componente em múltiplos slots em uma chamada:

import { ui } from "@tiendanube/nube-sdk-helper";

ui.renderAll(["corner_top_left", "corner_top_right"], {
type: "txt",
children: "Hi",
});
ui.showToast("Done!", "success");
ui.clear("corner_top_right");

onEvent e toastOn reduzem o padrão repetitivo de "escutar e reagir" a uma linha cada, ambos retornando uma função de cancelamento:

import { onEvent, toastOn } from "@tiendanube/nube-sdk-helper";

const off = onEvent("cart:update", (state) => {
console.log("items:", state.cart.items.length);
});

// Later, when you no longer need it:
off();

toastOn("cart:add:success", "Added to cart", "success");
toastOn("cart:update", (state) => `Cart: ${state.cart.items.length} items`);

Próximos passos

  • Events — Lista completa de eventos disponíveis no NubeSDK
  • State — Estrutura de estado do NubeSDK
  • UI Slots — Slots disponíveis para renderização

Help us improve NubeSDK

Found an issue or have a suggestion? Let us know on GitHub.