VTEX IO permite criar componentes React customizados e reutilizáveis. Vamos do setup à publicação.
O Que é VTEX IO?
VTEX IO é a plataforma de desenvolvimento da VTEX que permite:
- **Componentes React:** Frontend moderno
- **GraphQL:** Queries e mutations tipadas
- **Serverless:** Node services escaláveis
- **CDN Global:** Performance mundial
- **Hot Reload:** Desenvolvimento ágil
Setup Inicial
1. Instalar VTEX Toolbelt
```bash
npm install -g vtex
vtex login conta-vtex
```
2. Criar Workspace de Desenvolvimento
```bash
vtex use workspace-dev
```
3. Criar App Custom
```bash
vtex init
# Selecione: store > react-app-template
```
Estrutura de um App VTEX IO
```
my-custom-app/
├── manifest.json
├── store/
│ └── interfaces.json
├── react/
│ ├── package.json
│ ├── tsconfig.json
│ └── components/
│ └── CustomComponent.tsx
└── graphql/
└── schema.graphql
```
Exemplo 1: Componente de Banner Dinâmico
manifest.json
```json
{
"name": "custom-banner",
"vendor": "minhaloja",
"version": "0.1.0",
"title": "Custom Banner",
"description": "Banner dinâmico personalizável",
"builders": {
"react": "3.x",
"store": "0.x",
"docs": "0.x"
},
"dependencies": {
"vtex.store": "2.x",
"vtex.css-handles": "1.x"
},
"$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
}
```
store/interfaces.json
```json
{
"custom-banner": {
"component": "CustomBanner",
"composition": "children",
"allowed": "*"
}
}
```
react/components/CustomBanner.tsx
```typescript
import React from 'react';
import { useCssHandles } from 'vtex.css-handles';
interface CustomBannerProps {
title: string;
subtitle?: string;
imageUrl: string;
ctaText: string;
ctaLink: string;
backgroundColor?: string;
}
const CSS_HANDLES = [
'bannerContainer',
'bannerImage',
'bannerContent',
'bannerTitle',
'bannerSubtitle',
'bannerCta',
] as const;
const CustomBanner: React.FC<CustomBannerProps> = ({
title,
subtitle,
imageUrl,
ctaText,
ctaLink,
backgroundColor = '#000',
}) => {
const handles = useCssHandles(CSS_HANDLES);
return (
<div
className={handles.bannerContainer}
style={{ backgroundColor }}
>
<img
src={imageUrl}
alt={title}
className={handles.bannerImage}
/>
<div className={handles.bannerContent}>
<h2 className={handles.bannerTitle}>{title}</h2>
{subtitle && (
<p className={handles.bannerSubtitle}>{subtitle}</p>
)}
<a
href={ctaLink}
className={handles.bannerCta}
>
{ctaText}
</a>
</div>
</div>
);
};
// Schema para Site Editor
CustomBanner.schema = {
title: 'Custom Banner',
description: 'Banner personalizável',
type: 'object',
properties: {
title: {
title: 'Título',
type: 'string',
default: 'Bem-vindo',
},
subtitle: {
title: 'Subtítulo',
type: 'string',
},
imageUrl: {
title: 'URL da Imagem',
type: 'string',
widget: {
'ui:widget': 'image-uploader',
},
},
ctaText: {
title: 'Texto do Botão',
type: 'string',
default: 'Comprar agora',
},
ctaLink: {
title: 'Link do Botão',
type: 'string',
default: '#',
},
backgroundColor: {
title: 'Cor de Fundo',
type: 'string',
widget: {
'ui:widget': 'color',
},
},
},
};
export default CustomBanner;
```
Estilização com CSS Handles
```css
/* styles.css */
.bannerContainer {
position: relative;
width: 100%;
min-height: 400px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.bannerImage {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 0;
}
.bannerContent {
position: relative;
z-index: 1;
text-align: center;
color: white;
padding: 2rem;
}
.bannerTitle {
font-size: 3rem;
font-weight: bold;
margin-bottom: 1rem;
}
.bannerSubtitle {
font-size: 1.5rem;
margin-bottom: 2rem;
}
.bannerCta {
display: inline-block;
padding: 1rem 2rem;
background: #fff;
color: #000;
text-decoration: none;
border-radius: 4px;
font-weight: bold;
transition: transform 0.2s;
}
.bannerCta:hover {
transform: scale(1.05);
}
```
Exemplo 2: Componente com GraphQL
graphql/schema.graphql
```graphql
type Product {
id: ID!
name: String!
price: Float!
image: String
}
type Query {
featuredProducts(limit: Int): [Product]
}
```
react/components/FeaturedProducts.tsx
```typescript
import React from 'react';
import { useQuery } from 'react-apollo';
import gql from 'graphql-tag';
const GET_FEATURED_PRODUCTS = gql`
query FeaturedProducts($limit: Int) {
featuredProducts(limit: $limit) {
id
name
price
image
}
}
`;
interface FeaturedProductsProps {
limit?: number;
}
const FeaturedProducts: React.FC<FeaturedProductsProps> = ({ limit = 4 }) => {
const { data, loading, error } = useQuery(GET_FEATURED_PRODUCTS, {
variables: { limit },
});
if (loading) return <div>Carregando...</div>;
if (error) return <div>Erro ao carregar produtos</div>;
return (
<div className="featured-products">
<h2>Produtos em Destaque</h2>
<div className="products-grid">
{data.featuredProducts.map((product: any) => (
<div key={product.id} className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p>R$ {product.price.toFixed(2)}</p>
</div>
))}
</div>
</div>
);
};
FeaturedProducts.schema = {
title: 'Produtos em Destaque',
type: 'object',
properties: {
limit: {
title: 'Quantidade de Produtos',
type: 'number',
default: 4,
},
},
};
export default FeaturedProducts;
```
Testando Localmente
1. Link o app
```bash
vtex link
```
2. Acesse seu workspace
```
https://workspace-dev--conta.myvtex.com
```
3. Adicione no Site Editor
1. Acesse Admin VTEX
2. Storefront > Site Editor
3. Adicione seu componente na página
Publicando o App
1. Versione o app
```bash
vtex release patch stable
```
2. Publique
```bash
vtex publish
```
3. Instale em produção
```bash
vtex install vendor.app-name@version
```
4. Promova workspace (ou vá direto para master)
```bash
vtex workspace promote
# ou
vtex use master
vtex install vendor.app-name@version
```
Boas Práticas
1. TypeScript Sempre
✅ Use tipos:
```typescript
interface Props {
title: string;
items: Array<{
id: string;
name: string;
}>;
}
```
2. CSS Handles para Customização
✅ Permita que lojistas customizem:
```typescript
const handles = useCssHandles(['container', 'title', 'item']);
```
3. Schema Completo
✅ Facilite configuração no Site Editor:
```typescript
Component.schema = {
title: 'Nome Amigável',
description: 'Descrição clara',
properties: {
// Todos os props configuráveis
},
};
```
4. Performance
✅ Otimize imagens:
```typescript
import { Image } from 'vtex.store-image';
<Image
src={imageUrl}
width={800}
height={600}
loading="lazy"
/>
```
5. Testes
✅ Teste em múltiplos dispositivos:
- Desktop
- Tablet
- Mobile
Troubleshooting
Erro: "Builder not found"
**Solução:** Adicione o builder no manifest.json
Erro: "Schema validation failed"
**Solução:** Verifique sintaxe do schema.graphql
Hot reload não funciona
**Solução:** Reinicie o vtex link
Componente não aparece no Site Editor
**Solução:** Verifique interfaces.json
Recursos
- **Documentação:** https://developers.vtex.com/
- **Store Framework:** https://developers.vtex.com/docs/guides/vtex-io-documentation-what-is-vtex-store-framework
- **CSS Handles:** https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization
- **GraphQL:** https://developers.vtex.com/docs/guides/graphql-ide
Conclusão
VTEX IO oferece um ecossistema poderoso para criar componentes customizados:
- **React moderno:** Hooks, TypeScript, CSS-in-JS
- **Performance:** CDN global, code splitting automático
- **DX excelente:** Hot reload, type safety
- **Lojista-friendly:** Site Editor drag-and-drop
Próximos passos:
1. Crie seu primeiro componente simples
2. Teste no workspace de desenvolvimento
3. Adicione GraphQL se precisar de dados
4. Publique e compartilhe
Precisa de ajuda com VTEX IO? [Entre em contato](/contato).